zoukankan      html  css  js  c++  java
  • POJ 1149 PIGS 最大流

    第一次做网络流,看着教材里面的题解做的= =

    用的是Ford,应该是最好理解的把,就是不断的找有没有从源点到汇点的增广路然后更新。

    建图真是难啊,而且感觉细节要注意的地方比较多,一开始没有考虑反向弧,WA了两发,sad...

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <climits>
    #include <string>
    #include <iostream>
    #include <map>
    #include <cstdlib>
    #include <list>
    #include <set>
    #include <queue>
    #include <stack>
    
    using namespace std;
    
    typedef long long LL;
    const int INF = INT_MAX / 4;
    const int maxn = 305;
    const int maxm = 3005;
    int n,m,s,t;
    int A[maxn],K[maxn][maxm],B[maxn];    //A为每个顾客有的钥匙数量,K为钥匙的类型,B为顾客的需求
    int P[maxm],firstp[maxm];    //猪圈中猪的数量,每个猪圈的第一个客户
    int dist[maxn][maxn];
    
    void input() {
        for(int i = 1;i <= m;i++) {
            scanf("%d",&P[i]);
        }
        for(int i = 1;i <= n;i++) {
            scanf("%d",&A[i]);
            for(int j = 1;j <= A[i];j++) {
                scanf("%d",&K[i][j]);
            }
            scanf("%d",&B[i]);
        }
    }
    
    void init() {
        s = 0; t = n + 1;
        memset(firstp,0,sizeof(firstp));
        memset(dist,0,sizeof(dist));
        for(int i = 1;i <= n;i++) {
            for(int j = 1;j <= A[i];j++) {
                if(firstp[K[i][j]] == 0) {
                    firstp[K[i][j]] = i;
                    dist[s][i] += P[K[i][j]];
                }
                else {
                    dist[firstp[K[i][j]]][i] = INF;
                    firstp[K[i][j]] = i;
                }
            }
            dist[i][t] = B[i];
        }
    }
    
    int flow[maxn][maxn];   //流量
    int alpha[maxn],pre[maxn];      //每个点的可改进量和每个点的前驱
    int q[maxn],qs,qe;      //队列
    
    //Ford-Fulkerson
    void solve() {
        memset(flow,0,sizeof(flow));
        alpha[s] = INF;
        while(1) {
            //初始化标号
            for(int i = 1;i <= t;i++) pre[i] = -2;
            pre[s] = -1;
            //初始化队列,源点入列
            qs = 0; qe = 1;
            q[qs] = s;
            //标号过程
            while(qs < qe && pre[t] == -2) {    //终点没有被标号并且队列非空
                int v = q[qs]; qs++;
                //printf("now v is %d
    ",v);
                for(int i = 1;i <= t;i++) {
                    //如果目标点没有被标号并且还有残余流量
                    if(pre[i] == -2 && dist[v][i] - flow[v][i] != 0) {
                        pre[i] = v;
                        alpha[i] = min(alpha[v],dist[v][i] - flow[v][i]);
                        q[qe++] = i;
                    }
                }
            }
            //没有找到到汇点的增广路,退出
            if(pre[t] == -2) {
                break;
            }
            //逆向更新
            int aval = alpha[t];
            for(int i = t;pre[i] != -1;i = pre[i]) {
                flow[pre[i]][i] += aval;
                flow[i][pre[i]] = -flow[pre[i]][i];
            }
        }
        //统计流量
        int ans = 0;
        for(int i = 1;i <= n;i++) {
            ans += flow[i][t];
        }
        printf("%d
    ",ans);
    }
    
    int main() {
        while(scanf("%d%d",&m,&n) != EOF) {
            input();
            init();
            solve();
        }
        return 0;
    }
    

      

  • 相关阅读:
    cookie和session学习笔记
    Listener和Filter学习笔记
    [转载]mysql root密码忘了怎么办
    [转载]oracle连不上的各种现象
    Oauth入门学习
    XML学习笔录
    共享内存
    守护进程
    Linux系统调用与文件I/O(一)
    我的第一篇博客
  • 原文地址:https://www.cnblogs.com/rolight/p/3868116.html
Copyright © 2011-2022 走看看