线性规划与网络流24题 05圆桌问题

建立二分图,每个单位为X集合中的顶点,每个餐桌为Y集合中的顶点,增设附加源S和汇T。

1、从S向每个Xi顶点连接一条容量为该单位人数的有向边。
2、从每个Yi顶点向T连接一条容量为该餐桌容量的有向边。
3、X集合中每个顶点向Y集合中每个顶点连接一条容量为1的有向边。

求网络最大流,如果最大流量等于所有单位人数之和,则存在解,否则无解。对于每个单位,从X集合对应点出发的所有满流边指向的Y集合的顶点就是该单位人员的安排情况(一个可行解)。

这个题是多解也就是求出来的只是一个可行解。。。。所以测数据可能有的会错。。。。简单题。。。


#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define inf 1<<30
#define N 100000
#define cc(m,v) memset(m,v,sizeof(m))
struct node{
    int u,v,f,next;
}edge[N];
int head[1000],p,lev[1000],cur[1000];
int que[N];
void ainit(){
    p=0,cc(head,-1);
}
bool bfs(int s,int t){
    int i,u,v,qin=0,qout=0;
    cc(lev,-1),lev[s]=0,que[qin++]=s;
    while(qout!=qin){
        u=que[qout++];
        for(i=head[u];i!=-1;i=edge[i].next)
            if(edge[i].f>0 && lev[v=edge[i].v]==-1){
                lev[v]=lev[u]+1,que[qin++]=v;
                if(v==t) return 1;
            }
    }
    return 0;
}
int dinic(int s,int t){
    int i,k,u,qin,f;
    int flow=0;
    while(bfs(s,t)){
        memcpy(cur,head,sizeof(head));
        u=s,qin=0;
        while(1){
            if(u==t){
                for(k=0,f=inf;k<qin;k++)
                    if(edge[que[k]].f<f) f=edge[que[i=k]].f;
                for(k=0;k<qin;k++)
                    edge[que[k]].f-=f,edge[que[k]^1].f+=f;
                flow+=f,u=edge[que[qin=i]].u;
            }
            for(i=cur[u];cur[u]!=-1;i=cur[u]=edge[cur[u]].next)
                if(edge[i].f>0 && lev[u]+1==lev[edge[i].v]) break;
            if(cur[u]!=-1)
                que[qin++]=cur[u],u=edge[cur[u]].v;
            else{
                if(qin==0) break;
                lev[u]=-1,u=edge[que[--qin]].u;
            }
        }
    }
    return flow;
}
void addedge(int u,int v,int f){
    edge[p].u=u,edge[p].v=v,edge[p].f=f,edge[p].next=head[u],head[u]=p++;
    edge[p].u=v,edge[p].v=u,edge[p].f=0,edge[p].next=head[v],head[v]=p++;
}
int main(){
    int n,m,i,u,s,t,j,sum,sum1;
    while(scanf("%d%d",&m,&n)!=-1 && m){
        ainit();
        s=0,t=n+m+1,sum=0,sum1=0;
        for(i=1;i<=m;i++){
            scanf("%d",&u);
            addedge(s,i,u);
            sum+=u;
        }        
        for(i=m+1;i<t;i++){
            scanf("%d",&u);
            addedge(i,t,u);
            sum1+=u;
        }
        for(i=1;i<=m;i++)
            for(j=t-1;j>=1+m;j--)
                addedge(i,j,1);
        if(sum<=sum1 && dinic(s,t)==sum){
            printf("1\n");
            for(i=1;i<=m;i++){
                for(j=head[i];j!=-1;j=edge[j].next)
                    if(edge[j].f==0 && edge[j].v!=0) printf("%d ",edge[j].v-m);
                printf("\n");
            }
        }else
            printf("0\n");
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值