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;
}

 

 

posted on 2013-08-14 11:28  Still_Raining  阅读(734)  评论(0编辑  收藏  举报