题目:城市间有若干条道路,士兵可以经过道路到相邻的城市,现在给定初始每个城镇的士兵数目和最终的数目,问是否可以达到最终局面。
思路:关键是建图,首先从源点到初始城镇连边,然后把有边的初始城镇和结束城镇连边,最后把结束城镇和汇点连边,这样就可以保证题目中的“每个士兵最多经过一条道路”的条件,然后求出最大流,如果与城镇总人数相等,那么就有解。输出解的时候只需要把反向边的流量输出即可。
#include<iostream> #include<map> #include<algorithm> #include<cstdio> #include<cstring> #include<cstdlib> #include<vector> #include<queue> #include<stack> #include<functional> #include<set> #include<cmath> #define pb push_back #define fs first #define se second #define sq(x) (x)*(x) #define eps 0.0000000001 #define IINF (1<<30) using namespace std; typedef long long ll; typedef pair<ll,ll> P; const int maxv=105*4; struct EDGE{ int to,cap,rev; EDGE(int t,int c,int r){ to=t,cap=c,rev=r; } }; vector<EDGE> G[maxv]; void addedge(int f,int t,int c){ G[f].pb(EDGE(t,c,G[t].size())); G[t].pb(EDGE(f,0,G[f].size()-1)); } int level[maxv],iter[maxv]; queue<int> Q; void bfs(int s){ memset(level,-1,sizeof level); level[s]=0; Q.push(s); while(!Q.empty()){ int v=Q.front();Q.pop(); for(int i=0;i<G[v].size();i++){ EDGE &e=G[v][i]; if(e.cap>0&&level[e.to]<0){ level[e.to]=level[v]+1; Q.push(e.to); } } } } int dfs(int v,int t,int f){ if(v==t) return f; for(int &i=iter[v];i<G[v].size();i++){ EDGE &e=G[v][i]; if(e.cap>0&&level[v]<level[e.to]){ int d=dfs(e.to,t,min(f,e.cap)); if(d>0){ e.cap-=d; G[e.to][e.rev].cap+=d; return d; } } } return 0; } int dinic(int s,int t){ int flow=0; while(1){ bfs(s); if(level[t]<0) return flow; memset(iter,0,sizeof iter); int f; while((f=dfs(s,t,IINF))>0){ flow+=f; } } } int a[maxv],b[maxv]; int n,m; int s=maxv-3,t=maxv-4; int sa=0,sb=0; int out[maxv][maxv]; int main(){ freopen("/home/files/CppFiles/in","r",stdin); /* std::ios::sync_with_stdio(false); std::cin.tie(0);*/ cin>>n>>m; for(int i=1;i<=n;i++){ scanf("%d",a+i); addedge(s,i,a[i]); addedge(i,i+n,IINF); sa+=a[i]; } for(int i=1;i<=n;i++){ scanf("%d",b+i); addedge(i+n,t,b[i]); sb+=b[i]; } for(int i=0;i<m;i++){ int p,q; scanf("%d%d",&p,&q); addedge(p,q+n,IINF); addedge(q,p+n,IINF); } int ans=dinic(s,t); for(int i=1;i<=n;i++){ for(int j=0;j<G[i].size();j++){ EDGE &e=G[i][j]; if(e.to-n>n) continue; EDGE &r=G[e.to][e.rev]; out[i][e.to-n]=r.cap; } } if(ans==sa&&sa==sb){ cout<<"YES"<<endl; for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ cout<<out[i][j]<<" "; } cout<<endl; } }else{ cout<<"NO"<<endl; } return 0; }