鏈接:https://cn.vjudge.net/problem/CodeForces-546E
題意:n個城市,每個城市初始時有a[i]個士兵。城市間有m條無向邊,某個城市的士兵可以留在原城市到或到與該城市僅僅相鄰的城市(即只隔一條路的士兵)。現在要求最終某個城市必須正好有b[i]個士兵,可能的話輸出n*n的矩陣,表示有mat[i][j]個士兵從城市i到城市j。
思路:因爲城市有初始數量和目標數量,有一個點有兩個相關值得話,就去想拆點。
1、城市(i)和源點(s)連邊,容量爲a[i]。
2、m條邊的兩個點之間連邊,u和v+n,u+n和v;容量爲inf。
3.城市(拆點:i+n)與匯點(t)連邊,容量爲b[i]。
跑一遍最大流即可。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 2e2+10;
const int M = 4e4+10;
const int inf = 0x3f3f3f3f;
struct node
{
int to,ca,nxt;
node(){}
node(int to,int ca,int nxt):to(to),ca(ca),nxt(nxt){}
}g[M];
int head[N],cnt;
int deep[N],cur[N];
int s,t,suma,sumb;
int n,m,u,v;
int a[N],b[N],mp[N][N];
void Init()
{
cnt=0;
s=0; t=n<<1|1;
for(int i=s;i<=t;i++)
head[i]=-1;
}
void add(int u,int v,int ca)
{
g[cnt]=node{v,ca,head[u]},head[u]=cnt++;
}
bool bfs()
{
queue<int> q;
for(int i=s;i<=t;i++)
deep[i]=0;
deep[s]=1;
q.push(s);
while(!q.empty())
{
u=q.front();
q.pop();
if(u==t) return 1;
for(int i=head[u];~i;i=g[i].nxt)
{
v=g[i].to;
if(!deep[v]&&g[i].ca>0)
{
deep[v]=deep[u]+1;
q.push(v);
}
}
}
return deep[t]!=0;
}
int getid(int x)
{
return x>n?x-n:x;
}
int dfs1(int u,int flow)
{
if(u==t||!flow) return flow;
int ans=0,nowflow;
for(int& i=cur[u];~i;i=g[i].nxt)
{
v=g[i].to;
if(deep[v]==deep[u]+1&&g[i].ca>0)
{
nowflow=dfs1(v,min(flow,g[i].ca));
if(nowflow)
{
ans+=nowflow;
flow-=nowflow;
g[i].ca-=nowflow;
g[i^1].ca+=nowflow;
if(!flow) break;
}
}
}
if(!ans) deep[u]=0;
return ans;
}
int dfs(int u,int flow)
{
if(u==t||!flow) return flow;
int v,nowflow;
for(int i=head[u];~i;i=g[i].nxt)
{
v=g[i].to;
if(deep[v]==deep[u]+1&&g[i].ca>0)
{
nowflow=dfs(v,min(flow,g[i].ca));
if(nowflow)
{
g[i].ca-=nowflow;
g[i^1].ca+=nowflow;
return nowflow;
}
}
}
return 0;
}
void dinic()
{
int maxflow=0,flow;
while(bfs())
{
memcpy(cur,head,sizeof(head));
while(flow=dfs1(s,inf))
maxflow+=flow;
}
if(maxflow!=sumb)
{
puts("NO");
return ;
}
puts("YES");
for(u=1;u<=n;u++)
for(int i=head[u];~i;i=g[i].nxt)
if(g[i].to>n&&g[i^1].ca>0)
mp[u][g[i].to-n]=g[i^1].ca;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
printf("%d%c",mp[i][j]," \n"[j==n]);
}
int main(void)
{
suma=0,sumb=0;
scanf("%d%d",&n,&m);
Init();
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),suma+=a[i];
for(int i=1;i<=n;i++)
scanf("%d",&b[i]),sumb+=b[i];
if(suma!=sumb)
{
puts("NO");
return 0;
}
for(int i=1;i<=n;i++)
{
add(s,i,a[i]);
add(i,s,0);
add(i,i+n,inf);
add(i+n,i,0);
add(i+n,t,b[i]);
add(t,i+n,0);
}
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
add(u,v+n,inf);
add(v+n,u,0);
add(v,u+n,inf);
add(u+n,v,0);
}
dinic();
return 0;
}