CF546E Soldier and Traveling
CF546E Soldier and Traveling
题意
给出一个无向图,第 \(i\) 个点上有 \(a_i\) 个士兵。每个士兵可以移动到跟自己相邻的点上,问是否可以使一些士兵移动后使得第 \(i\) 个点上有 \(b_i\) 个士兵,并给出方案。
思路
根据数据范围和标签我们可以大致猜到这是一道网络流题目。考虑该怎么建图。
我们可以建立二分图,其中左边部分的点表示原来的士兵,右边部分的点表示移动后的士兵,再建立超级源点和汇点 \(S,T\)。
显然原来 \(i\) 点士兵有 \(a_i\) 个,可以贡献 \(a_i\) 的容量;移动后 \(i\) 点士兵有 \(b_i\) 个,需要接受 \(b_i\) 的容量。于是我们将 \(S\) 与左部的第 \(i\) 个点连边,容量为 \(a_i\),将右边的点 \(i\) 与 \(T\) 连边,容量为 \(b_i\)。
对于每个点的士兵可以停留在原地,也可以移动到相邻的点。于是我们将左部 \(i\) 号点与右部 \(i\) 号点连边,这条边表示不动的士兵。对于原图上的无向边 \((i,j)\),我们将左部的 \(i\) 号点与右部的 \(j\) 号点连边,左部的 \(j\) 号点与右部的 \(i\) 号点连边,表示移动的士兵。因为可以移动任意数量的士兵,所以容量均为无限大。
跑完一遍网络流后,我们判一下 \(S\to i\) 与 \(j\to T\) 的边是否满流,若满流,则表示所有士兵都顺利转移,否则无解。求方案只需要看图上 \(i\to j\) 的每条边减少的流量即可。
代码
#include <bits/stdc++.h>
using namespace std;
namespace mf{
const int N=205,INF=0x3f3f3f3f;
struct node{
int x,w,rev;bool is;
};
vector<node> t[N];
int dep[N],gap[N],maxflow;
int n,m,S,T;
void add(int x,int y,int w){
t[x].push_back({y,w,t[y].size(),0});
t[y].push_back({x,0,t[x].size()-1,1});
}
void bfs(){
memset(gap,0,sizeof(gap));
memset(dep,-1,sizeof(dep));
queue<int> q;
q.push(T),dep[T]=0,gap[dep[T]]++;
while(!q.empty()){
int u=q.front();q.pop();
for(node v:t[u])
if(!~dep[v.x])
dep[v.x]=dep[u]+1,gap[dep[v.x]]++,q.push(v.x);
}
}
int dfs(int x,int flow){
if(x==T) return maxflow+=flow,flow;
int used=0;
for(auto&[v,w,rev,is]:t[x]){
if(w&&dep[v]+1==dep[x]){
int mn=dfs(v,min(w,flow-used));
if(mn) w-=mn,t[v][rev].w+=mn,used+=mn;
if(flow==used) return used;
}
}
gap[dep[x]]--;
if(!gap[dep[x]]) dep[S]=n+1;
dep[x]++,gap[dep[x]]++;
return used;
}
int isap(){
maxflow=0;
bfs();
while(dep[S]<n) dfs(S,INF);
return maxflow;
}
}
int n,m,ans[105][105];
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
cin>>n>>m;
int tot1=0,tot2=0;
mf::n=n*2+2,mf::S=n*2+1,mf::T=n*2+2;
for(int x,i=1;i<=n;i++)
cin>>x,mf::add(mf::S,i,x),mf::add(i,i+n,mf::INF),tot1+=x;
for(int x,i=1;i<=n;i++)
cin>>x,mf::add(i+n,mf::T,x),tot2+=x;
for(int x,y,i=1;i<=m;i++){
cin>>x>>y;
mf::add(x,y+n,mf::INF);
mf::add(y,x+n,mf::INF);
}
int res=mf::isap();
if(tot1==tot2&&tot2==res){
for(int i=1;i<=n;i++){
for(mf::node v:mf::t[i]){
if(v.is) continue;
ans[i][v.x-n]=mf::INF-v.w;
}
}
cout<<"YES"<<endl;
for(int i=1;i<=n;i++,cout<<endl)
for(int j=1;j<=n;j++)
cout<<ans[i][j]<<" ";
}
else cout<<"NO";
return 0;
}

浙公网安备 33010602011771号