原题: https://cn.vjudge.net/contest/259384#problem/F
题意:
n个插座,m个玩具,下面k行匹配关系,一个一般的插座只能插一个玩具,你可以使一个插座插三个玩具,求最大匹配数
解析:
首先对插座做一遍匈牙利,匹配完之后,再枚举每个插座,看看是不是可能再插两个玩具(也是匈牙利,因为我的匈牙利考虑的是玩具的匹配,所以可以直接对插座做匈牙利,相当于这个插座可以再多匹配一个玩具)
当然,枚举一个插座的时候,不能改变原来的玩具的匹配数组,所以要新开一个tmp数组
按照这种思路,如果遇到某些插座可以匹配k个玩具的题目,就直接对这些插座做k次匈牙利即可
当然,这时的匈牙利要进行修改来避免死循环
#include<bits/stdc++.h>
using namespace std;
const int N=1600;
int match[N];
bool vis[N];
bool link[N][N];
int f[N];
bool v[N];
int n,m;
int fin(int h){
for(int i=1;i<=m;i++){
if(vis[i]||!link[h][i])continue;
vis[i]=1;
if(match[i]==0||fin(match[i])){
match[i]=h;return 1;
}
}
return 0;
}
int tmp[N];
int fin2(int h){
for(int i=1;i<=m;i++){
if(vis[i]||!link[h][i])continue;
vis[i]=1;
if(tmp[i]!=h&&(tmp[i]==0||fin2(tmp[i]))){//避免死循环
tmp[i]=h;return 1;
}
}
return 0;
}
int main(){
memset(match,0,sizeof(match));
int t;
scanf("%d%d%d",&n,&m,&t);
for(int i=1,a,b;i<=t;i++)scanf("%d%d",&a,&b),link[a][b]=1;
int ans=0;
for(int i=1;i<=n;i++){//插座
memset(vis,0,sizeof(vis));
if(fin(i))ans++;//最大匹配数
}
int ma=0;
for(int i=1;i<=n;i++){
int add=0;
for(int j=1;j<=m;j++)tmp[j]=match[j];
memset(vis,0,sizeof(vis));
if(fin2(i)){
add++;
memset(vis,0,sizeof(vis));
if(fin2(i)){
add++;
}
}
ma=max(ma,add);
}
printf("%d\n",ma+ans);
}