• 题意
    • 给定一些点上的初始士兵数ai,问能否通过相邻间的互相移动(只能邻边之间移动一次),达到每个点的目标士兵数bi。
  • 题解
    • 经典最大流模型
      • 源点si边权为ai
      • ij(j==i或者j与i相邻)边权为>=a[i]即可
      • j→t边权为bj
    • 我们注意到题目中的限制,只能移动一次或者不移动,可以看作i向i或者i向j直接移动一次
    • 于是我们可以将j(j=i或者j与i相邻)点直接建立在新的层上,这样就防止了大于一次的移动,这里拆点与点边转化稍有不同,因为入点只入,出点只出,更像是为了满足限制而拆点,整个网络共有2*n+2个点,
    • 另外,该边为双向边,我们需要正反加边
    • 因为最后的结果是所有的点,所以总和不变,第一步可先判断sum[ai]是否等于sum[bi]
    • 跑出了最大流之后,只需要判定总和是否为sum[ai]即可,因为到汇点的最大容量为sum[bi](sum[ai]=sum[bi])时,即使使得连接汇点的边的容量跑满,即满足目标容量
    • 本题数据量小,跑E-K即可
    • 图中红色边为输入的反向边,而非反向弧,未标注的容量皆为>=ai
  • 代码
    • //#include<bits/stdc++.h>
      #include<iostream>
      #include<cstdio>
      #include<cstring>
      #include<string>
      #include<set>
      #include<vector>
      #include
      <map>
      #include<stack>
      #include<queue>
      #include<cmath>
      #include<fstream>
      #include<algorithm>
      using namespace std;
      
      #define rep(i,a,n) for(int i=a;i<=n;i++) #define per(i,a,n) for(int i=n;i>=a;i--)
      #define CLR(a) memset(a,0,sizeof(a))
      
      typedef long long ll;
      typedef unsigned long long ull;
      
      const int INF = 0x3f3f3f3f;
      
      const int maxn=2010;
      const int maxm=6000;
      int tot=-1;//因为要利用成对的特性,所以只能从奇数开始,然后++tot作为第一条边
      int head[maxn],ver[maxm],edge[maxm],Next[maxm];
      int ans[1010][1010];
      int v[maxn],incf[maxn],pre[maxn];
      void addedge(int u,int v,int w) {
      	ver[++tot]=v,edge[tot]=w,Next[tot]=head[u],head[u]=tot;
      	ver[++tot]=u,edge[tot]=0,Next[tot]=head[v],head[v]=tot;
      }
      int maxflow=0;
      int n,m;
      int a[maxn];
      int b[maxn];
      int S,T;
      
      
      bool bfs() {
      	memset(v,0,sizeof(v));
      	queue<int>q;
      	q.push(S);
      	v[S]=1;
      	incf[S]=INF;
      	while(q.size()) {
      		int x = q.front();
      		q.pop();
      		for(int i=head[x]; i!=-1; i=Next[i]) {
      			if(edge[i]) {
      				int y = ver[i];
      				if(v[y])continue;
      				incf[y]=min(incf[x],edge[i]);
      				pre[y]=i;
      				q.push(y),v[y]=1;
      				if(y==T)return 1;
      			}
      		}
      	}
      	return 0;
      }
      
      void update() {
      	int x=T;
      	while(x!=S) {
      		int i=pre[x];;
      		edge[i]-=incf[T];
      		edge[i^1]+=incf[T];
      		x = ver[i^1];
      	}
      	maxflow += incf[T];
      }
      int main() {
      	memset(head,-1,sizeof(head));
      	scanf("%d%d", &n,&m);
      	S=0,T=n*2+1;
      	int s1=0,s2=0;
      	rep(i,1,n) {
      		scanf("%d", &a[i]);
      		addedge(S,i,a[i]);
      		s1+=a[i];
      	}
      	rep(i,1,n) {
      		scanf("%d", &b[i]);
      		addedge(i,i+n,a[i]);//因为i节点前的流量只有a[i],所以i到i与i到j的流量上限只有a[i],所以上限只要大于a[i]即可
      		addedge(i+n,T,b[i]);
      		s2+=b[i];
      	}
      	if(s1!=s2) {
      		puts("NO");
      		return 0;
      	}
      	int u,v;
      	rep(i,1,m) {
      		scanf("%d%d", &u,&v);
      		addedge(u,v+n,a[u]);
      		addedge(v,u+n,a[v]);
      	}
      	while(bfs())update();
      	if(maxflow!=s1) {
      		puts("NO");
      		return 0;
      	}
      	printf("YES\n");
      	rep(i,1,n)
      		for(int j=head[i];j!=-1;j=Next[j])
      			if(ver[j]>n) ans[i][ver[j]-n]=a[i]-edge[j];
      	rep(i,1,n){
      		rep(j,1,n-1)
      			printf("%d ",ans[i][j]);
      		printf("%d\n",ans[i][n]);
      	}
      	return 0;
      }

       

发表评论

邮箱地址不会被公开。 必填项已用*标注