终于把匈牙利搞懂了。。。
题目大意
有 个客人, 个房间, 个菜肴,每个人都有自己喜欢的房间和菜肴,问最多能满足多少个人的需求。
解题思路
这是一道二分图最大匹配题。
对于每个客人喜欢的菜肴,可以从客人连一条有向边到他喜欢的菜肴;
对于每个客人喜欢的房间,可以从客人连一条有向边到他喜欢的房间;
判断是否能满足第 个客人的需求,我们只需要跑 次匈牙利算法进行二分图匹配即可(第一次是菜肴的匹配,第二次是房间的匹配)
如果符合(两次都可以成功匹配),那么就统计;
否则的话,就要回溯(也就是把数组恢复到匹配前的状态),要不然可能会在不能满足客人需求的同时且改变以前的匹配。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,p,q;
vector<int> a[501];
vector<int> e[501];
int last1[501],vis1[501];
bool dfs(int x)
{
if(vis1[x])
return 0;
vis1[x]=1;
for(auto y:a[x])
{
if(last1[y]==0||dfs(last1[y]))
{
last1[y]=x;
return 1;
}
}
return 0;
}
int last2[501],vis2[501];
bool dfs2(int x)
{
if(vis2[x])
return 0;
vis2[x]=1;
for(auto y:e[x])
{
if(last2[y]==0||dfs2(last2[y]))
{
last2[y]=x;
return 1;
}
}
return 0;
}
int aa[501],bb[501];
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>p>>q;
int x;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=p;j++)
{
cin>>x;
if(x)
{
a[i].push_back(j);
}
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=q;j++)
{
cin>>x;
if(x)
{
e[i].push_back(j);
}
}
}
int ans=0;
for(int i=1;i<=n;i++)
{
memset(vis1,0,sizeof vis1);
memset(vis2,0,sizeof vis2);
memcpy(aa,last1,sizeof last1);
memcpy(bb,last2,sizeof last2);
if(dfs(i)&dfs2(i))
ans++;
else{
memcpy(last1,aa,sizeof aa);
memcpy(last2,bb,sizeof bb);
}
}
cout<<ans;
}