CF546E Soldier and Traveling(网络流,最大流)

CF546E Soldier and Traveling

题目描述

In the country there are \(n\) cities and \(m\) bidirectional roads between them. Each city has an army. Army of the i-th city consists of \(a_{i}\) soldiers. Now soldiers roam. After roaming each soldier has to either stay in his city or to go to the one of neighboring cities by at moving along at most one road.

Check if is it possible that after roaming there will be exactly \(b_{i}\) soldiers in the i-th city.

输入输出格式

输入格式:

First line of input consists of two integers n n n and m m m ( \(1<=n<=100\) , \(0<=m<=200\) ).

Next line contains \(n\) integers \(a_{1},a_{2},...,a_{n}\) ( \(0<=a_{i}<=100\) ).

Next line contains \(n\) integers \(b_{1},b_{2},...,b_{n}\)​ ( \(0<=b_{i}<=100\) ).

Then m lines follow, each of them consists of two integers p and q ( \(1<=p,q<=n , p≠q\) ) denoting that there is an undirected road between cities p and q .

It is guaranteed that there is at most one road between each pair of cities.

输出格式:

If the conditions can not be met output single word "NO".

Otherwise output word "YES" and then n n n lines, each of them consisting of n integers. Number in the i-th line in the j-th column should denote how many soldiers should road from city i to city j(if i≠j ) or how many soldiers should stay in city i (if i=j ).

If there are several possible answers you may output any of them.

输入输出样例

输入样例#1: 复制

4 4
1 2 6 3
3 5 3 1
1 2
2 3
3 4
4 2

输出样例#1: 复制

YES
1 0 0 0
2 0 0 0
0 5 1 0
0 0 2 1

输入样例#2: 复制

2 0
1 2
2 1

输出样例#2: 复制

NO



题解


题意大概就是给你 \(n\) 个城市,\(m\) 条边。
然后人只能从走相邻边相连的城市。
现在给你初始城市的每一个人数,再给一组每个城市人数。询问是否可以从当前人数变换到给定人数。如果能,输入“YES”并输出方案,不能则输出“NO”。

网络流就是建图嘛。。。
建好图一般就没有什么难度了qwq(dalao雾怼)
那么怎么建呢?
我们设一个源点和汇点。
然后把一个城市拆成两个点。
入点 \(i\) 限度设为 \(a_i\) ,出点 \(i+n\) 限度设为 \(b_{i}\)
这样就只要判断汇点的最大流是否与 \(b_i\) 相等了。
Ps: 原本的人数和后来方案的人数应该相等,且一定要先判定。

怎么输出方案?
看反悔路径的流量就好了。
有就标记一下并输出。



代码


#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
const int N=1001;
struct node{
    int c,to,next;
}e[N<<1];
int num=1,head[N<<3],flag;
int dep[N<<3],n,m,a[N<<3],b[N<<3],sum,tot,s,t;
int map[N][N];
int read(){
    int x=0,w=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*w;
}

void add(int from,int to,int c){
    num++;
    e[num].to=to;
    e[num].c=c;
    e[num].next=head[from];
    head[from]=num;
}

bool bfs(){
    memset(dep,0,sizeof(dep));
    queue<int>q;q.push(s);dep[s]=1;
    while(!q.empty()){
        int u=q.front();q.pop();
        for(int i=head[u];i;i=e[i].next){
            int v=e[i].to;
            if(!dep[v]&&e[i].c){
                dep[v]=dep[u]+1;q.push(v);
            }
        }
    }
    return dep[t];
}

int dfs(int x,int cap){
    if(x==t)return cap;
    int addx=0;
    for(int i=head[x];i;i=e[i].next){
        int v=e[i].to;
        if(dep[v]==dep[x]+1&&e[i].c){
            int tmp=dfs(v,min(cap-addx,e[i].c));
            e[i].c-=tmp;e[i^1].c+=tmp;addx+=tmp;
        }
    }
    return addx;
}

int dinic(){
    int ans=0;
    while(bfs())ans+=dfs(s,10000000);
    return ans;
}

int main()
{
    n=read();m=read();s=0,t=n+n+1;
    for(int i=1;i<=n;i++)a[i]=read(),add(s,i,a[i]),add(i,s,0),tot+=a[i];
    for(int i=1;i<=n;i++)b[i]=read(),sum+=b[i],add(i+n,t,b[i]),add(t,i+n,0);
    for(int i=1;i<=n;i++)add(i,i+n,99999999),add(i+n,i,0);
    for(int i=1;i<=m;i++){
        int x=read(),y=read();
    //  if(x<y)swap(x,y);
        add(x,y+n,99999999);add(y+n,x,0);
        add(y,x+n,99999999);add(x+n,y,0);
    }
    //cout<<sum<<' '<<dinic();
    if(tot!=sum){printf("NO");return 0;}
    int ans=dinic();
    if(sum==ans){printf("YES\n");
        for(int i=1;i<=n;i++){
            for(int j=head[i];j;j=e[j].next){
                int v=e[j].to;
                if(v>n)
                map[i][v-n]=e[j^1].c;
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++)
            cout<<map[i][j]<<' ';
            cout<<endl;
        }
    }
    else printf("NO");
    return 0;
}

转载于:https://www.cnblogs.com/hhh1109/p/9362553.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值