zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    2013第五周上机任务【项目1 三角形类(构造函数)】
    Google搜索小技巧
    项目总结:文件上传(MVC uploadify)
    Oracle 触发器 Update 不能操作本表的疑问
    【笔试题STL】求两个vector的交集
    Zookeeper(六)数据模型
    是的,我们真的在遭遇有史以来最大的DDoS攻击,并且还在加剧
    在MFC框架下使用osg报内存泄露的解决办法
    NetBeans 时事通讯(刊号 # 107 Jun 25, 2010)
    VS 2008中的C/C++静态代码分析工具Prefast
  • 原文地址:https://www.cnblogs.com/hanruyun/p/10630182.html
Copyright © 2011-2022 走看看