1. 程式人生 > >Soldier and Traveling 【CodeForces - 546E】【網路流最大流】

Soldier and Traveling 【CodeForces - 546E】【網路流最大流】

題目連結


  超級好的一道網路流求最大流的問題,挺考驗思維的,我們在這道題的難點就是怎麼建圖。

  建圖是一項巨大的工程,要知道我們的基礎狀態是一開始的狀態,我定義為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;
}