题目链接。
分析:
这题描述的可不是一般的复杂.
其时就是很多源点、很多汇点,使尽量多流量的到达汇点。
因为有很多源点,就再设一个源点(0号),使得0号到其它源点的容量为其它源点的初始量,同样设一汇点(n+1),使得其它汇点到该汇点的容量为其它汇点的初始量,如此就把很多的源点和汇点看成普通的点,单源单汇最大流。
最大流用的是白书上的增广路算法。
AC代码如下:
#include <iostream> #include <queue> #include <cstdio> #include <cstring> #include <vector> using namespace std; const int maxn = 110; const int INF = (1<<30); int cap[maxn][maxn], flow[maxn][maxn]; int EdmondsKarp(int s, int t, int n) { int p[maxn], a[maxn]; queue<int> q; memset(flow, 0, sizeof(flow)); int f = 0; while(true) { memset(a, 0, sizeof(a)); a[s] = INF; q.push(s); while(!q.empty()) { //BFS 找增广路 int u = q.front(); q.pop(); for(int v=1; v<=n; v++) if(!a[v] && cap[u][v]>flow[u][v]){ //找到新节点v p[v] = u; q.push(v); a[v] = min(a[u], cap[u][v]-flow[u][v]); } } if(a[t] == 0) break; //找不到,则当前流已经是最大流 for(int u=t; u != s; u = p[u]) { //从汇点往回走 flow[p[u]][u] += a[t]; //更新正向流量 flow[u][p[u]] -= a[t]; //更新反向流量 } f += a[t]; //更新从 s 流出的流量 } return f; } int main(){ int n, np, nc, m; int u, v, c; char s[200]; while(scanf("%d%d%d%d", &n, &np, &nc, &m) == 4) { memset(cap, 0, sizeof(cap)); for(int i=0; i<m; i++) { scanf("%s", s); sscanf(s, "(%d,%d)%d", &u, &v, &c); u++; v++; cap[u][v] += c; } for(int i=0; i<np; i++) { //处理源点 scanf("%s", s); sscanf(s, "(%d)%d", &v, &c); v++; cap[0][v] += c; } for(int i=0; i<nc; i++) { //处理汇点 scanf("%s", s); sscanf(s, "(%d)%d", &u, &c); u++; cap[u][n+1] += c; } printf("%d ", EdmondsKarp(0, n+1, n+1)); } return 0; }