E. Soldier and Traveling(CF546E) Codeforces Round #304 (Div. 2)

E. Soldier and Traveling
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

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 aisoldiers. 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 bi soldiers in the i-th city.

Input

First line of input consists of two integers n and m (1 ≤ n ≤ 1000 ≤ m ≤ 200).

Next line contains n integers a1, a2, ..., an (0 ≤ ai ≤ 100).

Next line contains n integers b1, b2, ..., bn (0 ≤ bi ≤ 100).

Then m lines follow, each of them consists of two integers p and q (1 ≤ p, q ≤ np ≠ 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.

Output

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

Otherwise output word "YES" and then 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.

Sample test(s)
input
4 4
1 2 6 3
3 5 3 1
1 2
2 3
3 4
4 2
output
YES
1 0 0 0 
2 0 0 0 
0 5 1 0 
0 0 2 1 
input
2 0
1 2
2 1
output
NO


题意:给你一张无向图,每个点有一定数量的人,通过移动可以去邻接点(但是只能移动一次)问你是否能从初始状态移动到目标状态;

 

思路:网络流+最大流;

 

转载请注明出处:寻找&星空の孩子

 

题目链接:http://codeforces.com/contest/546/problem/E

 

 

#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
#define captype int

const int MAXN = 510;   //点的总数
const int MAXM = 400010;    //边的总数
const int INF = 1<<30;
struct EDG{
    int to,next;
    captype cap,flow;
} edg[MAXM];
int eid,head[MAXN];
int gap[MAXN];  //每种距离(或可认为是高度)点的个数
int dis[MAXN];  //每个点到终点eNode 的最短距离
int cur[MAXN];  //cur[u] 表示从u点出发可流经 cur[u] 号边
int pre[MAXN];
int mapt[105][105];

void init(){
    eid=0;
    memset(head,-1,sizeof(head));
    memset(mapt,0,sizeof(mapt));
}
//有向边 三个参数,无向边4个参数
void addEdg(int u,int v,captype c,captype rc=0){
    edg[eid].to=v; edg[eid].next=head[u];
    edg[eid].cap=c; edg[eid].flow=0; head[u]=eid++;

    edg[eid].to=u; edg[eid].next=head[v];
    edg[eid].cap=rc; edg[eid].flow=0; head[v]=eid++;
}
captype maxFlow_sap(int sNode,int eNode, int n){//n是包括源点和汇点的总点个数,这个一定要注意
    memset(gap,0,sizeof(gap));
    memset(dis,0,sizeof(dis));
    memcpy(cur,head,sizeof(head));
    pre[sNode] = -1;
    gap[0]=n;
    captype ans=0;  //最大流
    int u=sNode;
    while(dis[sNode]<n){   //判断从sNode点有没有流向下一个相邻的点
        if(u==eNode){   //找到一条可增流的路
            captype Min=INF ;
            int inser;
            for(int i=pre[u]; i!=-1; i=pre[edg[i^1].to])    //从这条可增流的路找到最多可增的流量Min
            if(Min>edg[i].cap-edg[i].flow){
                Min=edg[i].cap-edg[i].flow;
                inser=i;
            }
            for(int i=pre[u]; i!=-1; i=pre[edg[i^1].to]){

                edg[i].flow+=Min;
                edg[i^1].flow-=Min;  //可回流的边的流量
                
                if(edg[i].to==eNode||edg[i].to==sNode||edg[i^1].to==eNode||edg[i^1].to==sNode)
                    continue;
                if(edg[i].cap>0){
                    int tu, tv;
                    tu=edg[i^1].to; tv=edg[i].to-(n-1)/2;
                    mapt[tu][tv]+=Min;
                }
                else{
                    int tu, tv;
                    tu=edg[i].to; tv=edg[i^1].to-(n-1)/2;
                    mapt[tu][tv]-=Min;
                }
                
            }
            ans+=Min;
            u=edg[inser^1].to;
            continue;
        }
        bool flag = false;  //判断能否从u点出发可往相邻点流
        int v;
        for(int i=cur[u]; i!=-1; i=edg[i].next){
            v=edg[i].to;
            if(edg[i].cap-edg[i].flow>0 && dis[u]==dis[v]+1){
                flag=true;
                cur[u]=pre[v]=i;
                break;
            }
        }
        if(flag){
            u=v;
            continue;
        }
        //如果上面没有找到一个可流的相邻点,则改变出发点u的距离(也可认为是高度)为相邻可流点的最小距离+1
        int Mind= n;
        for(int i=head[u]; i!=-1; i=edg[i].next)
        if(edg[i].cap-edg[i].flow>0 && Mind>dis[edg[i].to]){
            Mind=dis[edg[i].to];
            cur[u]=i;
        }
        gap[dis[u]]--;
        if(gap[dis[u]]==0) return ans;  //当dis[u]这种距离的点没有了,也就不可能从源点出发找到一条增广流路径
                                        //因为汇点到当前点的距离只有一种,那么从源点到汇点必然经过当前点,然而当前点又没能找到可流向的点,那么必然断流
        dis[u]=Mind+1;//如果找到一个可流的相邻点,则距离为相邻点距离+1,如果找不到,则为n+1
        gap[dis[u]]++;
        if(u!=sNode) u=edg[pre[u]^1].to;  //退一条边
    }
    return ans;
}
int main(){
    int n,m ,s , t , u,v,c[105],tc;
    while(scanf("%d%d",&n,&m)>0){
        init();
        s=0;
        t=2*n+1;
        int ans=0;
        for(int i=1; i<=n; i++){
            scanf("%d",&c[i]);
            ans+=c[i];
            addEdg(s,i,c[i]);
            addEdg(i,i+n,c[i]);
        }
        int sum=0;
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&tc); sum+=tc;
            addEdg(i+n,t,tc);
        }
        while(m--){
            scanf("%d%d",&u,&v);
            addEdg(u,v+n,c[u]);
            addEdg(v,u+n,c[v]);
        }
        if(ans!=sum){
            printf("NO\n"); continue;
        }
        ans -= maxFlow_sap(s,t,t+1);
        if(ans==0){
            printf("YES\n");
            for(int i=1; i<=n; i++){
                for(int j=1; j<n; j++)
                    printf("%d ",mapt[i][j]);
                printf("%d\n",mapt[i][n]);
            }
        }
        else
            printf("NO\n");
    }
}


 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值