http://blog.csdn.net/quailty/article/details/46571011
这题是一个比较明显的最大流,但是我试着建了几个图都没有找到很合适的。然后看到了我大q神的博客,瞬间茅塞顿开,在这里膜一波q神Orz
建图:
设置一个源点s ,然后建立s (0)到 1—-n 的边,容量cap为a[i]。 设置一个t,建立1+n — n+n 与 t(2*N+1)之间的路径,容量cap为b[i]。 (从源点到1-n 再到 1+n—n+n 再到t 的最大流图)
对于边 < i,j> 建立边 i—j+n ,容量为inf,再建立 j—–i+n,容量为inf。 表示这两条个城市之间可以相互通行
然后从0–2*n+1 跑一遍最大流,如果得出的最大流结果=a[i]的和=b[i]的和 那么结果就是YES。
主要是自己sb,在记录最终结果的时候脑残了一波,因为最大流不会管你从城市之间的道路走了几遍,他如果有增广路径就必然会走,哪怕这条路会绕来绕去绕好几个城市。 但是这个不会影响最终结果,回顾一下自己写的几个记录:
ans[x][i]=aa; //在这个地方记录一下增广的流
一开始就如果有x到i的流,就直接记录。
后来写成了:
if(x<=N){ //x在做 则 i在右
if(i>N)
ans[x][i-N]+=aa;
}
else{ //x在右,i必定在左
ans[x-N][i]-=aa; //这个地方减去
}
.....
现在看看感觉自己好蠢啊
这样完全是在XJB搞
最后写成:
ans[x][i]+=aa;
ans[i][x]-=aa;
这样就没有问题了,
输出的时候我们只要
for(int i=1;i<=N;i++){
for(int j=1+N;j<=N+N;j++){
printf("%d ",ans[i][j]);
}
ac代码:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#define mem(a) memset(a,0,sizeof(a))
#define INF 0x7fffffff //INT_MAX
#define inf 0x3f3f3f3f //
const double PI = acos(-1.0);
const double e = exp(1.0);
template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }
template<class T> inline T Min(T a, T b) { return a < b ? a : b; }
template<class T> inline T Max(T a, T b) { return a > b ? a : b;}
using namespace std;
int tab[250][250];//邻接矩阵
int dis[250];//距源点距离,分层图
int q[2000],h,r; //BFS队列 ,首,尾
int N,M,ANS;//N:点数;M,边数
int a[205],b[205];
int ans[205][205];
int BFS(){
int i,j;
memset(dis,-1,sizeof(dis));//以-1填充
dis[0]=0;
h=0;r=1;
q[1]=0;
while (h<r)
{
j=q[++h];
for (i=0;i<=N+N+1;i++){
if (dis[i]<0 && tab[j][i]>0){
dis[i]=dis[j]+1; //说明 i可以作为j的下一层
q[++r]=i;
}
}
}
if (dis[N+N+1]>0)
return 1;
else
return 0;//汇点的DIS小于零,表明BFS不到汇点
}
//Find代表一次增广,函数返回本次增广的流量,返回0表示无法增广
int find(int x,int low)
{
int i,aa=0;
if (x==N+N+1)
return low;//是汇点
for (i=0;i<=N+N+1;i++){
if (tab[x][i] >0 && dis[i]==dis[x]+1 //联通 //是分层图的下一层
&&(aa=find(i,min(low,tab[x][i]))) ) //
{
tab[x][i]-=aa;
tab[i][x]+=aa;
//在这个地方记录一下增广的流
ans[x][i]+=aa;
ans[i][x]-=aa;
// printf("操作的两个数:%d %d =%d\n",x,i,aa);
return aa;
}
}
return 0;
}
int main()
{
int i,j,f,t,tans;
//freopen("1.txt","r",stdin);
while (scanf("%d%d",&N,&M)!=EOF){
memset(tab,0,sizeof(tab));
mem(ans);
int sum_a=0,sum_b=0;
//以0 为s 2n+1 为 t;
for(i=1;i<=N;i++){
scanf("%d",&a[i]);
tab[0][i]=a[i];
sum_a+=a[i];
tab[i][i+N]=a[i]; //inf
}
for(i=1+N;i<=N*2;i++){
scanf("%d",&b[i]);
sum_b+=b[i];
tab[i][2*N+1]=b[i];
}
for (i=1;i<=M;i++){
scanf("%d%d",&f,&t);
tab[f][t+N]=inf;
tab[t][f+N]=inf;
}
if(sum_a!=sum_b){
printf("NO\n");
continue;
}
ANS=0;
while (BFS()){ //要不停地建立分层图,如果BFS不到汇点才结束
while(tans=find(0,inf))
ANS+=tans; //一次BFS要不停地找增广路,直到找不到为止
}
// printf("ANS=%d sum_a=%d\n",ANS,sum_a);
if(ANS!=sum_a){
printf("NO\n");
continue;
}
printf("YES\n");
for(int i=1;i<=N;i++){
for(int j=1+N;j<=N+N;j++){
printf("%d ",ans[i][j]);
}
printf("\n");
}
}
}