版权声明: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;
}