经典的二分图最大匹配问题,因为匈牙利算法我还没有认真去看过,想先试试下网络流的做法,即对所有女生增加一个超级源,对所有男生增加一个超级汇,然后按照题意的匹配由女生向男生连一条边,跑一个最大流就是答案(以上所有边容量均为 1 ),我是直接上 Dinic 算法的模板的:
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #include<queue> 5 #include<algorithm> 6 using namespace std; 7 #define sd(x) scanf("%d",&(x)) 8 const int inf = 0x3fffffff; 9 10 struct Edge { 11 int from, to, cap, flow; 12 Edge() {} 13 Edge(int from, int to, int cap, int flow): 14 from(from), to(to), cap(cap), flow(flow) {} 15 }; 16 17 const int N = 1003; 18 19 struct Dinic { 20 int s,t; 21 vector<Edge> edges; 22 vector<int> G[N]; 23 bool vis[N]; 24 int d[N]; 25 int cur[N]; 26 27 void clear() { 28 edges.clear(); 29 for(int i = 0; i < N; ++i) 30 G[i].clear(); 31 } 32 void addEdge(int from, int to, int cap) { 33 edges.push_back(Edge(from, to, cap, 0)); 34 edges.push_back(Edge(to, from, 0, 0)); 35 int m = edges.size(); 36 G[from].push_back(m - 2); 37 G[to].push_back(m - 1); 38 } 39 bool bfs() { 40 memset(vis,0,sizeof(vis)); 41 queue<int> q; 42 q.push(s); 43 d[s] = 0; 44 vis[s] = 1; 45 while(!q.empty()) { 46 int x = q.front(); q.pop(); 47 int len = G[x].size(); 48 for(int i = 0; i < len; ++i) { 49 Edge &e = edges[G[x][i]]; 50 if(!vis[e.to] && e.cap > e.flow) { 51 d[e.to] = d[x] + 1; 52 vis[e.to] = 1; 53 q.push(e.to); 54 } 55 } 56 } 57 return vis[t]; 58 } 59 int dfsAll(int x, int a) { 60 if(x == t || a == 0) return a; 61 int flow = 0, f, len = G[x].size(); 62 for(int &i = cur[x]; i < len; ++i) { 63 Edge &e = edges[G[x][i]]; 64 if(d[e.to] == d[x] + 1 && (f = dfsAll(e.to, min(a, e.cap - e.flow)) > 0)) { 65 e.flow += f; 66 edges[G[x][i]^ 1].flow -= f; 67 flow += f; 68 a -= f; 69 if(a == 0) break; 70 } 71 } 72 return flow; 73 } 74 int Maxflow(int s, int t) { 75 this->s = s; 76 this->t = t; 77 int flow = 0; 78 while(bfs()) { 79 memset(cur, 0, sizeof(cur)); 80 flow += dfsAll(s,inf); 81 } 82 return flow; 83 } 84 } dinic; 85 86 int c[1003]; 87 88 #define sd2(x,y) scanf("%d%d",&(x),&(y)) 89 #define sd3(x,y,z) scanf("%d%d%d",&(x),&(y),&(z)) 90 91 int main() { 92 int n,m,k,x,y; 93 while(~sd3(k, m, n), k) { 94 dinic.clear(); 95 while(k--) { 96 sd2(x,y); 97 y += m; 98 dinic.addEdge(x, y, 1); 99 // dinic.addEdge(y, x, 1); 100 } 101 for(int i = 1; i <= m; ++i) 102 dinic.addEdge(0, i, 1); 103 for(int i = m + 1; i <= m + n; ++i) 104 dinic.addEdge(i, m + n + 1, 1); 105 printf("%d ",dinic.Maxflow(0, m + n + 1)); 106 } 107 return 0; 108 }
需要注意的是男女生的编号,还有女生指向男生的是有向边,不需要两次的 addEdge。wa 了两次才找出所有问题。。。