AlenaNuna

导航

二分图最大匹配|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 个女生愿意结为配偶。保证 1vnl1≤v≤nl,1unr1≤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 号男生孤独终生。= =||

限制与约定

1nl,nr5001≤nl,nr≤500,1m2500001≤m≤250000。

时间限制1s1s

空间限制256MB


这个题目实际上就是二分图匹配的模板题。

 

--------
这里请允许我狠狠地吐槽《啊哈!算法》《信息学奥赛一本通》一类的野鸡书。语言很通俗,外表看起来很花俏没错,但错漏百出。《啊哈!算法》里面有相当一部分内容是有严重错误的,dijkstra、最小生成树、邻接表、匈牙利算法部分都有问题,甚至是代码问题,模板让你交上去wa成狗。
但我不得不说,上面两本书是适合新手的。
--------
这里用的是匈牙利算法,题目很老实没什么坑点。
注意:边表数组要开到500000以上,因为是无向图,要建两条边。
注意:match[i]存储i的配偶,1-n1是男方;n1+1-n1+n2是女方,结果要输出男方的配偶,也就是结果要输出match[i](1-n1)。
注意:对每一个点进行增广路时要判断那个点的配偶是否已经确认了,也就是判断match[i]是否为0。
注意:对每一个点进行增广路前要把用来标记的数组也就是book数组清0,再book[i]=1;意味着i点访问过了。
注意:输出的时候如果match[i]!=0match[i]要-n1,否则输出0,原因很简单,自己想。

讲讲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!

 

posted on 2017-08-29 20:34  AlenaNuna  阅读(316)  评论(0编辑  收藏  举报