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;
}
posted @ 2025-03-26 11:06  WuMin4  阅读(5)  评论(0)    收藏  举报