P3254 圆桌问题

Posted hanruyun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3254 圆桌问题相关的知识,希望对你有一定的参考价值。

题目链接

非常简单的一道网络流题

我们发现每个单位的人要坐到不同餐桌上,那也就是说每张餐桌上不能有同一单位的人。这样的话,我们对于每个单位向每张餐桌连一条边权为1的边,表示同一餐桌不得有相同单位的人。从源点向每个单位连一条边权为人数的边,从餐桌向汇点连一条边权为餐桌容量的边,这样的话跑最大流,跑出来的结果就是在满足以上条件的情况下最多能坐多少人,如果结果等于总人数,说明可行,否则不可行。

那么怎么输出方案呢?

我们记录每个单位向每张餐桌连的边的序号,如果这条边流满了,则说明这个单位有一个人坐在这张餐桌上。这样输出即可

下放代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define ll long long
#define gc getchar
#define maxn 505
#define maxm 100005
using namespace std;

inline ll read(){
    ll a=0;int f=0;char p=gc();
    while(!isdigit(p)){f|=p=='-';p=gc();}
    while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=gc();}
    return f?-a:a;
}int n,m,S,T,ans;

struct ahaha{
    int w,to,next;
}e[maxm<<1];int tot,head[maxn];
inline void add(int u,int v,int w){
    e[tot]={w,v,head[u]};head[u]=tot++;
}

int q[maxn],dep[maxn];
int bfs(){memset(dep,-1,sizeof dep);  //非常朴素的dinic
    int h=0,t=1;dep[S]=0;
    while(++h<=t){
        int u=q[h];
        for(int i=head[u];~i;i=e[i].next){
            int v=e[i].to;if(~dep[v]||e[i].w<=0)continue;
            dep[v]=dep[u]+1;q[++t]=v;
            if(v==T)return 1;
        }
    }return 0;
}
int dfs(int u,int w){
    if(u==T)return w;
    int sum=0;
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].to;if(dep[v]!=dep[u]+1||e[i].w<=0)continue;
        int d=dfs(v,min(w-sum,e[i].w));
        e[i].w-=d,e[i^1].w+=d;
        sum+=d;if(sum==w)break;
    }
    if(sum<w)dep[u]=-1;
    return sum;
}

int main(){memset(head,-1,sizeof dep);
    n=read();m=read();T=n+m+1;
    for(int i=1;i<=n;++i)  //因为先添加这种边,所以无需记录编号,直接计算得即可
        for(int j=1;j<=m;++j){
            add(i,j+n,1);
            add(j+n,i,0);
        }
    for(int i=1;i<=n;++i){
        int a=read();ans+=a;
        add(S,i,a);add(i,S,0);
    }
    for(int i=1;i<=m;++i){
        int a=read();
        add(n+i,T,a);add(T,n+i,0);
    }
    while(bfs())
        ans-=dfs(S,2147483647);
    if(ans){
        puts("0");
        return 0;
    }
    puts("1");
    for(int i=1;i<=n;++i,puts(""))  //这里就是上面说的输出方案
        for(int j=1;j<=m;++j){
            int p=((i-1)*m+j-1)*2;
            if(e[p].w)continue;
            printf("%d ",j);
        }
    return 0;
}

以上是关于P3254 圆桌问题的主要内容,如果未能解决你的问题,请参考以下文章

洛谷 P3254 圆桌问题最大流

luogu P3254 圆桌问题 网络流24

[洛谷P3254] [网络流24题] 圆桌游戏

8/26 网络流Dinic算法+最小割+cf

圆桌问题 网络流Isap算法

圆桌十日冲刺之七