P3254 圆桌问题

Aimee

看起来就是个匹配问题

建模 超级源点和汇点是必须的,那么这样看来,我们把每个单位和每张桌子连一张容量为1的边,表示只能派一个人,超级源点和每个单位连对应人数的边,桌子同理,然后跑最大流并且检查最大流和人数就可以

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
int n,m,s,t;
int p=1;
int x,y,z;
int head[605];
long long Aimee;
queue<int> q;
struct e{
	int to;
	long long v;
	int ne;
}ed[200001];
void add(int f,int t,int v){
	ed[++p].ne=head[f];ed[p].to=t;ed[p].v=v;head[f]=p;
	ed[++p].ne=head[t];ed[p].to=f;ed[p].v=0;head[t]=p;
}
int vis[100001];
long long exf[100001];
int pre[10001];
int le[10001];
int fr[10001];
const long long inf=(1<<29);
bool bfs(){
	memset(le,-1,sizeof(le));
	while(!q.empty()){
		q.pop();
	}
	q.push(s);
	le[s]=0;
	fr[s]=head[s];
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int i=head[u];i;i=ed[i].ne){
			int v=ed[i].to;
			if(ed[i].v&&le[v]==-1){
				q.push(v);le[v]=le[u]+1;
				fr[v]=head[v];
				if(v==t) return 1;
			}
		}
	}
	return 0;
} 
long long dfs(int now,int tas){
	if(now==t) return tas;
	long long znx=0;
	for(int i=fr[now];i&&znx<tas;i=ed[i].ne){
		fr[now]=i;
		int v=ed[i].to;
		if(ed[i].v&&le[v]==le[now]+1){
			long long jdn=dfs(v,min(tas-znx,ed[i].v));
			if(!jdn) le[v]=-1;
			ed[i].v-=jdn;
			ed[i^1].v+=jdn;
			znx+=jdn;
		}
	}
	return znx;
}
long long znx;
long long dinic(){
	while(bfs()){
		while(znx=dfs(s,inf)){
			Aimee+=znx;
		}
	}
	return Aimee;
}
int sum;
int main(){
	scanf("%d%d",&m,&n);
	s=n+m+2;
	t=n+m+1;
	for(int i=1;i<=m;++i){
		scanf("%d",&x);
		add(s,i,x);
		sum+=x;
	}	
	for(int i=1;i<=n;++i){
		scanf("%d",&x);
		add(i+m,t,x);
	}
	for(int i=1;i<=m;++i){
		for(int j=1;j<=n;++j){
			add(i,j+m,1);
		}
	}
	int Archie=dinic();
	if(sum!=Archie){
		cout<<0;
		return 0;
	}
	cout<<1<<endl;
	for(int i=1;i<=m;++i){
		for(int j=head[i];j;j=ed[j].ne){
 			if(ed[j].to!=s&&ed[j].v==0){
			 cout<<ed[j].to-m<<" "; 
			 } 
		}
		cout<<endl;
	}
	return 0;
} 
posted @ 2021-05-09 20:02  Simex  阅读(39)  评论(0编辑  收藏  举报