网络流24题——10.圆桌问题

题目链接

https://www.luogu.org/problemnew/show/P3254

圆桌问题

与前一道试题库问题非常的向,我们借鉴他的思想,我们设单位的集合为A,桌子的集合为B,对于每个单位人数x,从S向A连一条流量为x的边,对于每张桌子能坐y个人,我们从B向T连流量为y的边,那么每一条S-A-B-T的路径表示这个单位的人坐在B这张桌子上,由于每张桌子每个单位只能坐一个人,所以所有A向所有B连流量为1的边,就做完了。

#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<iostream>
#define LL long long
#define INF (2139062143)
#define N (100001)
using namespace std;
int m,n,all,S,T,tot,ans,sum,x;
int f[N],a[N],nxt[N],head[N],cur[N],h[N],co[N]; 
template <typename T> void read(T&t) {
    t=0;
    bool fl=true;
    char p=getchar();
    while (!isdigit(p)) {
        if (p=='-') fl=false;
        p=getchar();
    }
    do {
        (t*=10)+=p-48;p=getchar();
    }while (isdigit(p));
    if (!fl) t=-t;
}
inline void add(int x,int y,int z){
    a[++tot]=y,nxt[tot]=head[x],head[x]=tot,f[tot]=z;
}
int DFS(int u,int maxflow){
    if (u==T) return maxflow;
    int used=0;
    for (int i=cur[u];~i;i=nxt[i]){
        cur[u]=i;
        if (f[i]&&h[a[i]]+1==h[u]){
            int now=DFS(a[i],min(maxflow-used,f[i]));
            used+=now;
            f[i]-=now;
            f[i^1]+=now;
            if (used==maxflow) return used;
        }
    }
    cur[u]=head[u];
    if (--co[h[u]]==0) h[S]=all;
    h[u]++;
    co[h[u]]++;
    return used;
}
int main(){
    read(m),read(n);
    all=m+n+2;
    S=m+n+1,T=m+n+2;
    tot=1;
    memset(head,-1,sizeof(head));
    memset(cur,-1,sizeof(cur));
    memset(h,0,sizeof(h));
    co[0]=all;
    for (int i=1;i<=m;i++){
        read(x);
        sum+=x;
        add(S,i,x);
        add(i,S,0); 
    }
    for (int i=1;i<=n;i++){
        read(x);
        add(i+m,T,x);
        add(T,i+m,0);
    }
    for (int i=1;i<=m;i++){
        for (int j=1;j<=n;j++){
            add(i,j+m,1);
            add(j+m,i,0);
        }
    }
    while (h[S]<all) ans+=DFS(S,INF);
    if (ans<sum){
        puts("0");
        return 0;
    }
    puts("1");
    for (int i=1;i<=m;i++){
        for (int p=head[i];~p;p=nxt[p]){
            if (f[p]==0&&a[p]!=S){
                printf("%d ",a[p]-m);
            }
        }
        puts(""); 
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值