题目链接:
http://codeforces.com/problemset/problem/546/E
E. Soldier and Traveling
memory limit per test256 megabytes
样例输出
YES
1 0 0 0
2 0 0 0
0 5 1 0
0 0 2 1
题意
给你n个点,m条边的图,每个点有a[i]个士兵,现在要重新部署士兵,每个士兵最多只能移动到相邻的点,问是否能移动成每个点有b[i]个士兵。
题解
最大流,把每个点拆成两个点,v,v',v与源点连容量为a[v],v'与汇点连容量为b[v],对于边(u,v),拆成(u,v'),(v,u')然后跑最大流。
代码
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define X first
#define Y second
#define mkp make_pair
#define lson (o<<1)
#define rson ((o<<1)|1)
#define mid (l+(r-l)/2)
#define sz() size()
#define pb(v) push_back(v)
#define all(o) (o).begin(),(o).end()
#define clr(a,v) memset(a,v,sizeof(a))
#define bug(a) cout<<#a<<" = "<<a<<endl
#define rep(i,a,b) for(int i=a;i<(b);i++)
#define scf scanf
#define prf printf
typedef __int64 LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<pair<int,int> > VPII;
const int INF=0x3f3f3f3f;
const LL INFL=0x3f3f3f3f3f3f3f3fLL;
const double eps=1e-8;
const double PI = acos(-1.0);
//start----------------------------------------------------------------------
const int maxn=222;
struct Edge{
int u,v,cap,flow;
Edge(int u,int v,int c,int f):u(u),v(v),cap(c),flow(f){}
};
struct Dinic{
int n,m,s,t;
vector<Edge> egs;
VI G[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn];
void init(int n){
this->n=n;
for(int i=0;i<n;i++) G[i].clear();
egs.clear();
}
void addEdge(int u,int v,int cap){
egs.pb(Edge(u,v,cap,0));
egs.pb(Edge(v,u,0,0));
m=egs.sz();
G[u].pb(m-2);
G[v].pb(m-1);
}
bool BFS(){
clr(vis,0);
queue<int> Q;
d[s]=0,Q.push(s),vis[s]=1;
while(!Q.empty()){
int x=Q.front(); Q.pop();
rep(i,0,G[x].sz()){
Edge& e=egs[G[x][i]];
if(!vis[e.v]&&e.cap>e.flow){
vis[e.v]=1;
d[e.v]=d[x]+1;
Q.push(e.v);
}
}
}
return vis[t];
}
int DFS(int x,int a){
if(x==t||a==0) return a;
int flow=0,f;
for(int &i=cur[x];i<G[x].sz();i++){
Edge& e=egs[G[x][i]];
if(d[x]+1==d[e.v]&&(f=DFS(e.v,min(a,e.cap-e.flow)))>0){
e.flow+=f;
egs[G[x][i]^1].flow-=f;
flow+=f;
a-=f;
if(a==0) break;
}
}
return flow;
}
int maxflow(int s,int t){
this->s=s;
this->t=t;
int flow=0;
while(BFS()){
clr(cur,0);
flow+=DFS(s,INF);
}
return flow;
}
int mat[maxn][maxn];
void print(int n){
clr(mat,0);
for(int i=0;i<m;i+=2){
Edge& e=egs[i];
if(e.flow>0&&e.cap==INF){
mat[e.u][e.v-n]+=e.flow;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
prf("%d",mat[i][j]);
if(j==n) prf("
");
else prf(" ");
}
}
}
}din;
int n,m;
int a[maxn],b[maxn];
int main() {
scf("%d%d",&n,&m);
int suma=0,sumb=0;
for(int i=1;i<=n;i++){
scf("%d",&a[i]);
suma+=a[i];
}
for(int i=1;i<=n;i++){
scf("%d",&b[i]);
sumb+=b[i];
}
if(suma!=sumb){
prf("NO
"); return 0;
}
din.init(n*2+2);
for(int i=1;i<=n;i++){
din.addEdge(0,i,a[i]);
din.addEdge(i+n,2*n+1,b[i]);
///这条边保证士兵能留在原来的城市
din.addEdge(i,i+n,INF);
}
rep(i,0,m){
int u,v;
scf("%d%d",&u,&v);
din.addEdge(u,v+n,INF);
din.addEdge(v,u+n,INF);
}
int ans=din.maxflow(0,2*n+1);
// bug(ans);
if(ans!=suma){
prf("NO
"); return 0;
}
prf("YES
");
din.print(n);
return 0;
}
//end-----------------------------------------------------------------------
Notes
这题一个关键的拆点没考虑到orz,,老是想着吧a[i]-b[i],但这思路好像是有问题的!,