链接:
http://poj.org/problem?id=1087
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=82835#problem/C
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=88230#problem/J (密码:0817)
n个插座,m个电器及其对应的插座,k个转化器,前一个插座可以转化为后一个插座,问最少有多少设备没有插座用,转换器数量不限
最大流,源点向插座建边,容量为1,电器向汇点建边,容量为1,相应的插座和电器连边,容量为1,前一个插座转化为后一个插座,
后一个插座向前一个插座建边,容量为无穷大,求得的最大流即为最多配对的电器。
网络流的部分是会了, 可是如何建图还是要学习
代码:
#include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespace std; #define N 1005 #define INF 0xfffffff int G[N][N], Layer[N]; char s[N][50]; bool CanLine(char s1[], char s2[]) ///判断转接口是否相同 { if(strcmp(s1, s2)==0) return true; return false; } bool BFS(int Start, int End) { queue<int>Q; Q.push(Start); memset(Layer, -1, sizeof(Layer)); Layer[Start] = 0; while(Q.size()) { int u = Q.front(); Q.pop(); if(u==End) return true; for(int i=1; i<=End; i++) { if(Layer[i]==-1 && G[u][i]) { Layer[i] = Layer[u] + 1; Q.push(i); } } } return false; } int DFS(int u, int MaxFlow, int End) { if(u==End) return MaxFlow; int uflow = 0; for(int i=1; i<=End; i++) { if(G[u][i] && Layer[i]==Layer[u]+1) { int flow = min(G[u][i], MaxFlow-uflow); flow = DFS(i, flow, End); G[u][i] -= flow; G[i][u] += flow; uflow += flow; if(uflow == MaxFlow) break; } } return uflow; } int Dinic(int Start, int End) { int MaxFlow = 0; while(BFS(Start, End)) MaxFlow += DFS(Start, INF, End); return MaxFlow; } int main() { int n, m, k; while(scanf("%d", &n)!=EOF) { int i, j; memset(G, 0, sizeof(G)); for(i=1; i<=n; i++) ///插头从1~n scanf("%s", s[i]); scanf("%d", &m); for(i=1; i<=m; i++) ///手机从n~n+m, 忽略手机的名字 scanf("%*s%s", s[i+n]); scanf("%d", &k); ///Ki是转换头进入的开始点, Kj是转换头出去的开始点, Start是源点,End是汇点 int Ki = n+m, Kj = Ki+k, Start = Kj+k+1, End = Start+1; for(i=1; i<=k; i++) ///转换器的进入n+m~n+m+k, 转换器的出从n+m+k~n+m+2*k { ///把入和出连接 scanf("%s%s", s[Ki+i], s[Kj+i]); G[Ki+i][Kj+i] = INF; ///转换器无限提供 } for(i=1; i<=m; i++) ///建立手机和转换器,插座的关系 { for(j=1; j<=n; j++) ///匹配一下手机和插座是否直接可以相连 if(CanLine(s[i+n], s[j])) G[i+n][j]=true; for(j=1; j<=k; j++) ///匹配一下手机和转换器入是否可以相连 if(CanLine(s[i+n], s[Ki+j])) G[i+n][Ki+j]=true; } for(i=1; i<=k; i++) ///建立转换器与转换器,插座的关系 { for(j=1; j<=k; j++) /// 匹配转换器与转换器入,转换器无限提供, 直接最大值 if(i!=j && CanLine(s[Kj+i], s[Ki+j])) G[Kj+i][Ki+j] = INF; for(j=1; j<=n; j++) /// 匹配转换器出和插座的关系 if(CanLine(s[Kj+i], s[j])==true) G[Kj+i][j] = true; } for(i=1; i<=m; i++) ///源点与手机的关系 G[Start][n+i] = true; for(i=1; i<=n; i++) ///插座与汇点的关系 G[i][End] = true; printf("%d\n", m-Dinic(Start, End)); } return 0; }
勿忘初心