zoukankan      html  css  js  c++  java
  • cf 546 E. Soldier and Traveling

    传送门
    给出每一个城市的初始人数,以及期望人数,每个人最多只能走一步。最后告诉城市的连接情况。
    如果可以,就输出yes,在输出(n^2)的矩阵,(i = j)时,输出第(i)个城市需要留几个人。否则输出(i)城市到(j)城市需要走几个人。

    建立一个超级源点和一个超级汇点,
    超级源点连接所有的城市,边权是(a_i),对于每一个城市再构建虚拟城市,与超级汇点连接,边权是(b_i)
    再把每一个城市和它的虚拟城市连接,边权是无穷大。
    再按照题目给的连接情况进行建边,边权是无穷大。

    然后跑最大流即可
    关于匹配情况,可以通过他的反向边来看,因为匹配时其实就3个点,那么反向边就是这个城市到那个城市的人数。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <queue>
    #define ll long long
    using namespace std;
    const int N = 200 + 5;
    const int M = 5e3 + 5;
    const int inf = 0x3f3f3f3f;
    template<typename T = long long> inline T read() {
        T s = 0, f = 1; char ch = getchar();
        while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
        while(isdigit(ch)) {s = (s << 3) + (s << 1) + ch - 48; ch = getchar();} 
        return s * f;
    }
    namespace MAX_FLOW {
        const int N = 200 + 5;
        int st, ed;
        struct Edge{
            int from, to, next, w;
        }e[M << 1];
        int head[N], tot = 1, cur[N]; //弧优化
        void add(int u, int v, int w){
            e[++tot].to = v;
            e[tot].from = u;
            e[tot].w = w;
            e[tot].next = head[u];
            head[u] = tot;
        }
        void add_edge(int u, int v, int w){
            add(u, v, w), add(v, u, 0);
        }
        int dis[N];
        int dfs(int u, int flow){ //保证了每次DFS都能找到增广路
            if(u == ed) return flow;
            int sum = 0;
            for(int i = cur[u]; i && flow; i = e[i].next){
                cur[u] = i;
                int v = e[i].to, w = e[i].w;
                if(w > 0 && dis[v] == dis[u] + 1){
                    int t = dfs(v, min(flow, w)); //获取这条增广路的最小流量
                    e[i].w -= t; e[i ^ 1].w += t; //减去最小流量,同时反向边加上最小流量
                    flow -= t; sum += t;
                }
            }
            if(!sum) dis[u] = 0;//结果u无法到达终点,或者没有增广路,切断经过这个点的路径
            return sum;
        }
        bool bfs(){//分层判断是否有增广路
            memset(dis, 0, sizeof(dis));
            queue<int> q;
            q.push(st); dis[st] = 1; cur[st] = head[st];//弧优化
            while(!q.empty()){
                int u = q.front(); q.pop();
                for(int i = head[u]; i; i = e[i].next){
                    int v = e[i].to, w = e[i].w;
                    if(w > 0 && !dis[v]) {
                        cur[v] = head[v];// v这个点从head[v]出发是可行的
                        dis[v] = dis[u] + 1;//分层
                        q.push(v);
                        if(v == ed) return 1;//已经到达增广路,直接返回
                    }
                }
            }
            return dis[ed];
        }
        ll Dinic(){
            ll max_flow = 0;
            while(bfs())
                max_flow += dfs(st, inf);
            return max_flow;
        }
    };
    int a[N], b[N];
    int ans[N][N];
    int main(){
        int n = read(), m = read(); int s = 0, t = 2 * n + 1;
        MAX_FLOW::st = s, MAX_FLOW::ed = t;
        int sum1 = 0, sum2 = 0;
        for(int i = 1; i <= n; i++) a[i] = read(), MAX_FLOW::add_edge(s, i, a[i]), sum1 += a[i];
        for(int i = 1; i <= n; i++) b[i] = read(), MAX_FLOW::add_edge(i + n, t, b[i]), sum2 += b[i];
        for(int i = 1; i <= n; i++) MAX_FLOW::add_edge(i, i + n, inf);
        for(int i = 1; i <= m; i++) {
            int u = read(), v = read();
            MAX_FLOW::add_edge(u, v + n, inf);
            MAX_FLOW::add_edge(v, u + n, inf);
        }
        if(sum1 != sum2) {
            printf("NO
    "); return 0;
        }
        ll max_flow = MAX_FLOW::Dinic();
        if(sum2 != max_flow) {
            printf("NO
    "); return 0;
        }
        for(int i = 4 * n + 2; i <= MAX_FLOW::tot; i += 2) {
            if(MAX_FLOW::e[i ^ 1].w) ans[MAX_FLOW::e[i].from][MAX_FLOW::e[i].to - n] = inf - MAX_FLOW::e[i].w; 
        }
        printf("YES
    ");
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
                printf("%d%c", ans[i][j], " 
    "[j == n]);
        return 0; 
    }
    
    I‘m Stein, welcome to my blog
  • 相关阅读:
    第一次设计作业
    项目选题报告(团队)
    第二次结队作业
    团队第一次作业
    原型设计(结对第一次)
    第二次作业——个人项目实战
    对于软件工程专业的思考
    电场与磁场
    透明层上的层或数字不透明
    Visiual Studio2012 CLR20r3问题
  • 原文地址:https://www.cnblogs.com/Emcikem/p/14349328.html
Copyright © 2011-2022 走看看