【题目】http://acm.hdu.edu.cn/showproblem.php?pid=3605
【大意】有n个人和m个星球,每个人有想去的星球,星球有最大容纳量,问能否给所有的人都安排上?
【思路】本来是最大流的题..但是n太大了,会T,看博客说要用状压...就学了一波匈牙利算法求二分图最大匹配...状压的写法有空补一补...
【参考】http://www.cppblog.com/JulyRina/archive/2015/02/13/209816.html(反了)
https://www.cnblogs.com/nanke/archive/2012/04/15/2450185.html
【二分图匹配】匈牙利算法https://blog.csdn.net/c20180630/article/details/70175814
就是让每一个男的直接匹配他清单上第一个女的,如果第一个被人匹配了,就去让那个男的找他的下一个女的,如果找到了,新来的男的就和这个女的匹配,否则这个男的就找下一个女的。
【二分图多重匹配】多重匹配就是女的可以找好几个老公,有上限。就把上面的改成:如果这个女的男票数量没有达到上上限,就直接匹配,否则尝试挤掉每一个她的男友,成功就匹配,失败就找下一个女的。
【匈牙利算法的代码】
//伪代码
bool dfs(int u)//寻找从u出发的增广路径
{
for each v∈u的邻接点
if(v未访问){
标记v已访问;
if(v未匹配||dfs(cy[v])){
cx[u]=v;
cy[v]=u;
return true;//有从u出发的增广路径
}
}
return false;//无法找到从u出发的增广路径
}
//代码
bool dfs(int u){
for(int v=1;v<=m;v++)
if(t[u][v]&&!vis[v]){
vis[v]=1;
if(cy[v]==-1||dfs(cy[v])){
cx[u]=v;cy[v]=u;
return 1;
}
}
return 0;
}
void maxmatch()//匈牙利算法主函数
{
int ans=0;
memset(cx,0xff,sizeof cx);
memset(cy,0xff,sizeof cy);
for(int i=0;i<=nx;i++)
if(cx[i]==-1)//如果i未匹配
{
memset(visit,false,sizeof(visit)) ;
ans += dfs(i);
}
return ans ;
}
【代码】
#include<cstdio>
#include<cstring>
const int Mn=100005;
const int Mm=15;
int mp[Mn][Mm];
int volume[Mm];//每个星球的容量
int n,m;
int ymatch[Mm][Mn];//ymatch[哪个星球][星上第几个人]=是谁
int cnt[Mn];//cnt[哪个星球]=已经住了多少人
bool vis[Mm];
bool dfs(int x)///仅仅是找x有没有能娶的
{
for(int i=0; i<m; i++)
{
if(vis[i])
continue;
if(mp[x][i]==0)
continue;
vis[i]=1;
if(cnt[i]<volume[i])//如果还能加人
{
ymatch[i][cnt[i]]=x;
cnt[i]++;
return 1;
}
else
{
for(int j=0; j<cnt[i]; j++)
{
if(dfs(ymatch[i][j]))
//如果本来配完的这个人还能去别的地方
{
ymatch[i][j]=x;
return 1;
}
}
}
}
return 0;
}
void hungary()
{
for(int i=0; i<n; i++)
{
memset(vis,0,sizeof(vis));
if(dfs(i)==0)
{
printf("NO\n");//只要有一个人不能匹配就no
return;
}
}
printf("YES\n");
return;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
memset(cnt,0,sizeof(cnt));
memset(mp,0,sizeof(mp));
for(int i=0; i<n; i++)
{
for(int j=0; j<m; j++)
{
int t;
scanf("%d",&t);
mp[i][j]=t;
}
}
for(int i=0; i<m; i++)
scanf("%d",&volume[i]);
hungary();
}
}