Soldier and Traveling 【CodeForces - 546E】【網路流最大流】
阿新 • • 發佈:2018-12-25
題目連結
超級好的一道網路流求最大流的問題,挺考驗思維的,我們在這道題的難點就是怎麼建圖。
建圖是一項巨大的工程,要知道我們的基礎狀態是一開始的狀態,我定義為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; }