二分图最大匹配|UOJ#78|匈牙利算法|边表|Elena
#78. 二分图最大匹配
从前一个和谐的班级,有 nlnl 个是男生,有 nrnr 个是女生。编号分别为 1,…,nl1,…,nl 和 1,…,nr1,…,nr。
有若干个这样的条件:第 vv 个男生和第 uu 个女生愿意结为配偶。
请问这个班级里最多产生多少对配偶?
输入格式
第一行三个正整数,nl,nr,mnl,nr,m。
接下来 mm 行,每行两个整数 v,uv,u 表示第 vv 个男生和第 uu 个女生愿意结为配偶。保证 1≤v≤nl1≤v≤nl,1≤u≤nr1≤u≤nr,保证同一个条件不会出现两次。
输出格式
第一行一个整数,表示最多产生多少对配偶。
接下来一行 nlnl 个整数,描述一组最优方案。第 vv 个整数表示 vv 号男生的配偶的编号。如果 vv 号男生没配偶请输出 00。
样例一
input
2 2 3 1 1 1 2 2 1
output
2 2 1
explanation
11 号男生跟 22 号女生幸福地生活在了一起~
22 号男生跟 11 号女生幸福地生活在了一起~
样例二
input
2 2 2 1 1 2 1
output
1 1 0
explanation
班上一个女神一个女汉子,两个男生都去追女神。一种最优方案是:
11 号男生跟 11 号女生幸福地生活在了一起~
22 号男生孤独终生。= =||
限制与约定
1≤nl,nr≤5001≤nl,nr≤500,1≤m≤2500001≤m≤250000。
时间限制:1s1s
空间限制:256MB
这个题目实际上就是二分图匹配的模板题。
讲讲dfs的代码。
bool dfs(int u)//寻找u节点的配偶
{
for (int i=head[u]; i; i=edge[i].next) //枚举以u为出点的每一条边
if (book[edge[i].to]==0) {//如果某个节点还没有访问过
book[edge[i].to]=1;//标记已访问过
if (match[edge[i].to]==0||dfs(match[edge[i].to])) {//match[edge[i].to]==0意味着edge[i].to点还没有配偶;如果edge[i].to点有配偶了,就dfs询问edge[i].to点的配偶能不能“让位”去找别的配偶。这里有点小三上位的意思。如果match[edge[i].to]点找到了新的配偶,就会和edge[i].to点离婚,这样子u点就可以和edge[i].to点在一起啦!
match[edge[i].to]=u;//标记互为配偶
match[u]=edge[i].to;
return 1;//找到配偶
}
}
return 0;//没有找到
}
我已经详细地解释了匈牙利代码的主要部分。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 int read() 8 { 9 int x=0,f=1; char c=getchar(); 10 while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();} 11 while (c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();} 12 return x*f; 13 } 14 long long sum; 15 int num_edge,head[1100],match[1100],u,v,n1,n2,m; 16 bool book[1100]; 17 struct Edge 18 { 19 int next; 20 int to; 21 }edge[510000]; 22 void add_edge(int from,int to) 23 { 24 edge[++num_edge].next=head[from]; 25 edge[num_edge].to=to; 26 head[from]=num_edge; 27 } 28 bool dfs(int u) 29 { 30 for (int i=head[u]; i; i=edge[i].next) 31 if (book[edge[i].to]==0) { 32 book[edge[i].to]=1; 33 if (match[edge[i].to]==0||dfs(match[edge[i].to])) { 34 match[edge[i].to]=u; 35 match[u]=edge[i].to; 36 return 1; 37 } 38 } 39 return 0; 40 } 41 int main() 42 { 43 n1=read(); n2=read(); m=read(); 44 for (int i=1; i<=m; i++) { 45 u=read(); v=read()+n1; 46 add_edge(u,v); 47 add_edge(v,u); 48 } 49 for (int i=1; i<=n1+n2; i++) { 50 for (int j=1; j<=n1+n2; j++) book[j]=0; 51 book[i]=1; 52 if (match[i]==0&&dfs(i)) sum++; 53 } 54 printf("%lld\n",sum); 55 for (int i=1; i<=n1; i++) 56 if (match[i]!=0) printf("%d ",match[i]-n1); 57 else printf("0 "); 58 return 0; 59 }
有问题可以直接在评论里面提问,有需要转载的请得到我的允许,否则按侵权处理。
Elena loves NiroBC forever!