• POJ-3436:ACM Computer Factory (Dinic最大流)


    题目链接:http://poj.org/problem?id=3436


    解题心得:

    • 题目真的是超级复杂,但解出来就是一个网络流,建图稍显复杂。其实提炼出来就是一个工厂n个加工机器,每个机器有一个效率w,q个材料入口,q个材料出口,每个口有三个数表示状态,1表示一定有入/出的材料,0表示没有入/出的材料,2表示可能有入的材料。如果一个机器入口全是0,代表这是起始机器,如果一个机器出口全是1,那么代表这是末尾机器。
    • 具体做法:
      • 将每个机器i拆成两点i和i+n分别代表进和出
      • 建立超级源点,连在起始机器上,流量INF。 建立超级汇点,找到末尾机器连在超级汇点上,流量INF。
      • 一个机器拆成的两个点i和i+n连上,流量就是这个点的效率w。
      • 然后暴力匹配,看一个点的所有出口是否可以完全对应一个点的入口,如果可以,匹配上,流量INF。
      • 跑Dinic,得到最大流。
    • 刚开始看到这个题没啥思路,因为关系太过于复杂,但是只要将题目中所有的关系提炼出来,就很容易建立一个网络图,要整体效率最大,那就是跑一个最大流啊,但是如果关系找漏GG。
    #include <stdio.h>
    #include <cstring>
    #include <stdlib.h>
    #include <queue>
    #include <math.h>
    #include <vector>
    #include <climits>
    using namespace std;
    const int maxn = 1e4+7;
    const int INF = INT_MAX;
    
    int p, n, S, T, level[maxn], iter[maxn];
    struct Machine {
        int in[15];
        int out[15];
        int p;
    }m[maxn];
    
    struct Edge {
        int to, cap, rev, flow;
        Edge(int To, int Cap, int Rev, int Flow):
                to(To), cap(Cap), rev(Rev), flow(Flow){}
    };
    
    vector <Edge> ve[maxn];
    
    
    void add_edge(int s,int t, int cap) {//建边
        ve[s].push_back(Edge(t, cap, ve[t].size(), 0));
        ve[t].push_back(Edge(s, 0, ve[s].size()-1, 0));
    }
    
    void build_edge() {//找出口和入口的关系
        for(int i=1;i<=n;i++) {
            for(int j=1;j<=n;j++) {
                if(i == j)
                    continue;
                bool flag = false;
                for(int k=1;k<=p;k++) {
                    if(m[j].in[k] != 2 && m[i].out[k] != m[j].in[k]) {
                        flag = true;
                        break;
                    }
                }
                if(!flag)
                    add_edge(i+n, j, INF);
            }
            add_edge(i, i+n, m[i].p);
        }
    }
    
    
    void init() {
        scanf("%d%d",&p,&n);
        S = 0, T = 2*n + 1;
        for(int i=1;i<=n;i++) {//找起始机器和末尾机器
            scanf("%d", &m[i].p);
            bool flag = false;
            for (int j = 1; j <= p; j++) {
                scanf("%d", &m[i].in[j]);
                if (m[i].in[j] == 1)
                    flag = true;
            }
            if (!flag)
                add_edge(S, i, INF);
            flag = false;
            for (int j = 1; j <= p; j++) {
                scanf("%d", &m[i].out[j]);
                if (m[i].out[j] != 1)
                    flag = true;
            }
            if (!flag)
                add_edge(i+n, T, INF);
        }
        build_edge();
    }
    
    
    bool bfs() {
        memset(level, -1, sizeof(level));
        level[S] = 0;
        queue <int> qu;
        qu.push(S);
        while(!qu.empty()) {
            int now = qu.front(); qu.pop();
            for(int i=0; i<ve[now].size(); i++) {
                Edge &e = ve[now][i];
                if(e.cap > e.flow && level[e.to] < 0) {
                    level[e.to] = level[now] + 1;
                    qu.push(e.to);
                }
            }
        }
        return  level[T] > 0;
    }
    
    int dfs(int now, int f) {
        if(now == T) return f;
        for(int &i=iter[now]; i<ve[now].size(); i++) {
            Edge &e = ve[now][i];
            if(e.cap > e.flow && level[e.to] > level[now]) {
                int d = dfs(e.to, min(f, e.cap-e.flow));
                if(d > 0) {
                    e.flow += d;
                    ve[e.to][e.rev].flow -= d;
                    return d;
                }
            }
        }
        return 0;
    }
    
    int max_flow() {//Dinic跑最大流
        int ans = 0;
        while(bfs()) {
            int f = dfs(S, INF);
            memset(iter, 0, sizeof(iter));
            if(f > 0)
                ans += f;
            else
                break;
        }
        return ans;
    }
    
    int cnt, path[maxn][5];
    void Print_path(int ans) {//把路找出来
        cnt = 0;
        for(int i=n+1;i<=2*n;i++) {
            for(int j=0;j<ve[i].size();j++) {
                Edge &e = ve[i][j];
                if(e.flow > 0 && e.to <= n) {
                    path[cnt][0] = i - n;
                    path[cnt][1] = e.to;
                    path[cnt][2] = e.flow;
                    cnt++;
                }
            }
        }
        printf("%d %d
    ",ans, cnt);
        for(int i=0;i<cnt;i++)
            printf("%d %d %d
    ",path[i][0], path[i][1], path[i][2]);
    }
    
    int main() {
        init();
        int ans = max_flow();
        Print_path(ans);
    }

  • 相关阅读:
    springcloud+openfeign+naocs实现服务和服务之间灰度调用
    mysql 负数转正数的处理以及java的处理
    ShardingSphereJDBC进行分库分表
    Shell脚本简单示例
    OpenSSL的升级
    Docker使用tomcat部署java项目
    Docker部署node服务
    docker部署Django项目
    delphi TMS FlexCel介绍
    delphi Excel控件介绍
  • 原文地址:https://www.cnblogs.com/GoldenFingers/p/9497667.html
Copyright © 2020-2023  润新知