Codeforces Round #304 (Div. 2)(CF546E) Soldier and Traveling(最大流)

发布时间:2020-10-03 发布网站:编程之家
编程之家收集整理的这篇文章主要介绍了Codeforces Round #304 (Div. 2)(CF546E) Soldier and Traveling(最大流)编程之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

题意

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

http://codeforces.com/contest/546/problem/E

思路

当∑a!=∑b时,肯定不能。

建一个超级源点s和超级汇点t,s到(1~n)连一条容量为a[i]的边,(n+1~2*n)到t连一条容量为b[i]的边,再将图中给定相连的边连容量为inf的边,比如u和v相连,那么u到v+n和v到u+n都要连容量为inf的边。还要将自己跟自己连边,即i到i+n连一条容量为inf的边,因为自己点的人不走相当于自己点走到自己点。最后都连上反向边用Dinic跑最大流,如果最大流==∑a,那么能,方案可以根据i到i+n的反向边的流量来求解。

样例的建图类似下面这样(随便画的):

分享图片

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int inf=1e9;
const int N=505;
int n,m,x,y,z,maxflow,deep[N];//deep深度
struct Edge
{
    int next,to,dis;
} edge[N*10];
int num_edge=-1,head[N],cur[N];//cur用于复制head
queue <int> q;

void add_edge(int from,int to,int dis,bool flag)
{
    edge[++num_edge].next=head[from];
    edge[num_edge].to=to;
    if (flag) edge[num_edge].dis=dis;//反图的边权为 0
    head[from]=num_edge;
}

//bfs用来分层
bool bfs(int s,int t)
{
    memset(deep,0x7f,sizeof(deep));
    while (!q.empty()) q.pop();
    for (int i=0; i<=2*n+1; i++) cur[i]=head[i];
    deep[s]=0;
    q.push(s);

    while (!q.empty())
    {
        int now=q.front();
        q.pop();
        for (int i=head[now]; i!=-1; i=edge[i].next)
        {
            if (deep[edge[i].to]>inf && edge[i].dis)//dis在此处用来做标记 是正图还是返图
            {
                deep[edge[i].to]=deep[now]+1;
                q.push(edge[i].to);
            }
        }
    }
    if (deep[t]<inf) return true;
    else return false;
}

//dfs找增加的流的量
int dfs(int now,int t,int limit)//limit为源点到这个点的路径上的最小边权
{
    if (!limit || now==t) return limit;

    int flow=0,f;
    for (int i=cur[now]; i!=-1; i=edge[i].next)
    {
        cur[now]=i;
        if (deep[edge[i].to]==deep[now]+1 && (f=dfs(edge[i].to,t,min(limit,edge[i].dis))))
        {
            flow+=f;
            limit-=f;
            edge[i].dis-=f;
            edge[i^1].dis+=f;
            if (!limit) break;
        }
    }
    return flow;
}

void Dinic(int s,int t)
{
    while (bfs(s,t))
        maxflow+=dfs(s,inf);
}
int a[N],b[N];
int main()
{
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&m);
    int s1=0,s2=0,s=0,t=2*n+1;
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&a[i]);
        add_edge(s,i,a[i],1);
        add_edge(i,s,0);
        s1+=a[i];
    }
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&b[i]);
        add_edge(i+n,b[i],1);
        add_edge(t,i+n,0);
        s2+=b[i];
    }
    for (int i=1; i<=m; i++)
    {
        scanf("%d%d",&x,&y);
        add_edge(x,y+n,inf,1);
        add_edge(y+n,0);
        add_edge(y,x+n,1);
        add_edge(x+n,0);
    }
    if(s1!=s2)
    {
        puts("NO");
        return 0;
    }
    for(int i=1;i<=n;i++)
    {
        add_edge(i,1);add_edge(i+n,0);
    }
    Dinic(s,t);
   // cout<<maxflow<<endl;
    if(maxflow==s1)
    {
        puts("YES");
        int g[N][N];
        for(int i=1;i<=n;i++)
        {
            for(int j=head[i];~j;j=edge[j].next)
            {
                int v=edge[j].to;
                if(v>n)
                {
                    g[i][v-n]=edge[j^1].dis;
                }
            }
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                printf("%d ",g[i][j]);
            }
            puts("");
        }
    }
    else
    {
        puts("NO");
    }
    return 0;
}

总结

以上是编程之家为你收集整理的Codeforces Round #304 (Div. 2)(CF546E) Soldier and Traveling(最大流)全部内容,希望文章能够帮你解决Codeforces Round #304 (Div. 2)(CF546E) Soldier and Traveling(最大流)所遇到的程序开发问题。

如果觉得编程之家网站内容还不错,欢迎将编程之家网站推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您喜欢交流学习经验,点击链接加入编程之家官方QQ群:1065694478
编程之家官方公众号

微信公众号搜索 “ 程序精选 ” ,选择关注!

微信公众号搜索 “ 程序精选 ”
精选程序员所需精品干货内容!