POJ3436 ACM Computer Factory(最大流)
题目链接。
分析:
题意很难懂。
大体是这样的:给每个点的具体情况,1.容量 2。进入状态 3.出去状态。求最大流。
因为有很多点,所以如果一个点的出去状态满足另一个点的进入状态,则这两个点可以连一条边。容量为两者容量的较小值。
再建立一个超源、一个超汇。让超源与所有进入状态全为0或者不全为0但只包含0和2的点连边,同时让所有出去状态全部为1的与超汇连边。
然后求最大流.
#include <iostream> #include <cstdio> #include <cstring> #include <queue> using namespace std; const int maxn = 60; const int INF = (1<<29); int in[maxn][12], cap[maxn][maxn], n, flow[maxn][maxn]; int EK(int s, int t) { queue<int> q; int p[maxn], a[maxn]; int f = 0; memset(flow, 0, sizeof(flow)); while(true) { memset(a, 0, sizeof(a)); a[s] = INF; q.push(s); while(!q.empty()) { int u = q.front(); q.pop(); for(int v = 0; v < n; v++) if(!a[v] && cap[u][v] > flow[u][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]; } return f; } int main() { int p; while(scanf("%d%d", &p, &n) == 2) { memset(cap, 0, sizeof(cap)); for(int i=0; i<2*p+1; i++) { //初始化超源,超汇 in[0][i] = 0; in[n+1][i] =1; } for(int i=1; i<=n; i++) { //输入数据 for(int j=0; j<2*p+1; j++) { scanf("%d", &in[i][j]); } } n+=2; //点数+2 for(int i=0; i<n; i++) { //将可以连通的点,记录,算出每条边的容量 for(int j=0; j<n; j++) { if(i == j) continue; bool flag = true; for(int k=1; k<=p; k++) { if( !((in[j][k] == 2) || (in[i][k+p] == in[j][k])) ) { flag = false; } } if(flag && i == 0) cap[i][j] = in[j][0]; else if(flag && j == n-1) cap[i][j] = in[i][0]; else if(flag) cap[i][j] += min(in[i][0], in[j][0]); } } printf("%d ", EK(0, n-1)); //增广路算法 int cnt = 0; //计数 for(int i=1; i<n-1; i++) { for(int j=1; j<n-1; j++) { if(flow[i][j] > 0) cnt++; } } printf("%d\n", cnt); for(int i=1; i<n-1; i++) { //输出 for(int j=1; j<n-1; j++) { if(flow[i][j] > 0) printf("%d %d %d\n", i, j, flow[i][j]); } } } return 0; }