Soldier and Traveling 【CodeForces - 546E】【网络流最大流】

版权声明:https://blog.csdn.net/qq_41730082 https://blog.csdn.net/qq_41730082/article/details/84943909

题目链接


  超级好的一道网络流求最大流的问题,挺考验思维的,我们在这道题的难点就是怎么建图。

  建图是一项巨大的工程,要知道我们的基础状态是一开始的状态,我定义为fir[]状态,后面往后走,我们需要让这个点变成我们想让它成为的状态,我称之为las[]状态,那么我们对于一个数的初始态,我们要做出限流,当然,对于终止状态,我们也需要限流,就是流到汇点的时候只能是我们想要的答案,那么,如何建立对应的边?

  建边,我们可以考虑最后的要求解是通过自己本身得到的,或者是通过别人的边链接过来再得到的,那么我们可以这样处理自己的边:0->(原值)->i->(∞)->N+i->(理想值)->tot(终点)。当有别的点连边过来的时候,我们可以把它连在N+i之后的边上,因为限流的是最后的那条边,就可以变成:u->(∞)->N+v,表示从u->v存在路。

  然后,输出那个极度困难的矩阵!那么看到这个边,如果有构成边的话,那么相对应u->v的消耗流就是用极限值减去u->(∞)->N+v的值,同理,自己到自己的也是这样的,可以建图自己多考虑下。


#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int INF = 1e9 + 7;
const int maxN = 205;
int N, M, fir[maxN], las[maxN], r[maxN][maxN], flow[maxN], pre[maxN], sum_1, sum_2, tot;
queue<int> Q;
int bfs(int st, int ed)
{
    while(!Q.empty()) Q.pop();
    memset(pre, -1, sizeof(pre));
    pre[st] = 0;
    flow[st] = INF;
    Q.push(st);
    while(!Q.empty())
    {
        int u = Q.front();  Q.pop();
        if(u == ed) break;
        for(int i=1; i<=tot; i++)
        {
            if(r[u][i] && pre[i] == -1)
            {
                pre[i] = u;
                flow[i] = min(r[u][i], flow[u]);
                Q.push(i);
            }
        }
    }
    return pre[ed]==(-1)?(-1):flow[ed];
}
int maxFlow(int st, int ed)
{
    int incr = 0, sumFlow = 0;
    while( (incr = bfs(st, ed)) != -1 )
    {
        int k = ed;
        while(k != st)
        {
            int last = pre[k];
            r[last][k] -= incr;
            r[k][last] += incr;
            k = last;
        }
        sumFlow += incr;
    }
    return sumFlow;
}
int main()
{
    while(scanf("%d%d", &N, &M)!=EOF)
    {
        sum_1 = sum_2 = 0;
        tot = 2 * N + 1;
        memset(r, 0, sizeof(r));    //初始化流为0
        for(int i=1; i<=N; i++) { scanf("%d", &fir[i]); sum_1 += fir[i]; r[0][i] = fir[i]; r[i][i+N] = INF; }
        for(int j=1; j<=N; j++) { scanf("%d", &las[j]); sum_2 += las[j]; r[N+j][tot] = las[j]; }
        for(int i=1; i<=M; i++)
        {
            int e1, e2;
            scanf("%d%d", &e1, &e2);
            r[e1][e2+N] = r[e2][e1+N] = INF;
        }
        if(sum_1 != sum_2 || maxFlow(0, tot)!=sum_2) { printf("NO\n"); continue; }
        printf("YES\n");
        for(int i=1; i<=N; i++)
        {
            for(int j=N+1; j<=2*N; j++)
            {
                printf("%d%s", r[i][j]==0?(0):(INF - r[i][j]), j==2*N?(""):(" "));
            }
            printf("\n");
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41730082/article/details/84943909
今日推荐