洛谷P3254 圆桌问题
作者:互联网
题目大意:
有\(m\)个单位,每个单位有\(r_i\)个人
共有\(n\)个桌子,每张桌子可以容纳\(c_i\)个人
现在要求每个单位每张桌子只能做一个人,求满足要求的方案
\(m\le 150,n\le 270\)
二分图多重匹配,这里采用网络流解法
单位作为二分图的左部,桌子作为二分图右部
由于每个单位每张桌子只能坐一个人,所以每个单位向每个桌子连一条容量为\(1\)的边。
源点向每个单位连容量为\(r_i\)的边,每张桌子向汇点连容量为\(c_i\)的边,跑一下最大流,看看最大流是否等于\(\sum\limits_{i=1}^{m}r_i\)
统计答案直接枚举
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int x=0,f=1;
char ch;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-') f=0,ch=getchar();
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return f?x:-x;
}
const int inf=0x7f7f7f7f;
int n,m,st,ed,ret,sum;
int head[10010],cur[10010],d[10010],cnt=1;
struct node
{
int nxt,to,val;
}a[100010];
inline void add(int x,int y,int z)
{
a[++cnt].nxt=head[x];
a[cnt].to=y;
a[cnt].val=z;
head[x]=cnt;
}
queue<int> q;
inline bool bfs()
{
for(int i=1;i<=n+m+2;++i)
{
cur[i]=head[i];
d[i]=0;
}
q.push(st);d[st]=1;
while(!q.empty())
{
int now=q.front();
q.pop();
for(int i=head[now];i;i=a[i].nxt)
{
int t=a[i].to;
if(!d[t]&&a[i].val)
{
d[t]=d[now]+1;
q.push(t);
}
}
}
return d[ed];
}
inline int dfs(int now,int c)
{
if(now==ed||!c) return c;
int ret=c,f;
for(int i=cur[now];i;i=a[i].nxt)
{
cur[now]=i;
int t=a[i].to;
if(d[t]==d[now]+1)
{
f=dfs(t,min(a[i].val,ret));
if(!f) continue;
a[i].val-=f;
a[i^1].val+=f;
ret-=f;
if(!ret) return c;
}
}
if(c==ret) d[now]=0;
return c-ret;
}
inline void dinic()
{
while(bfs()) ret+=dfs(st,inf);
if(ret!=sum)//最大流是否等于人数
{
puts("0");
return;
}
puts("1");
for(int x=1;x<=m;++x)
{
for(int i=head[x];i;i=a[i].nxt)
{
int t=a[i].to;
if(t<=m||t>n+m||a[i].val) continue;
printf("%d ",t-m);
}
putchar('\n');
}
}
signed main()
{
m=read(),n=read();
st=n+m+1,ed=n+m+2;
for(int x,i=1;i<=m;++i)//每个单位和源点连边,边权为人数
{
x=read();
add(st,i,x);
add(i,st,0);
sum+=x;
}
for(int x,i=1;i<=n;++i)//每张桌子和汇点连边,边权为容量
{
x=read();
add(i+m,ed,x);
add(ed,i+m,0);
for(int j=1;j<=m;++j)//单位和桌子连边,边权为1限制人数
{
add(j,i+m,1);
add(i+m,j,0);
}
}
dinic();
return 0;
}
标签:ch,洛谷,int,每张,单位,桌子,圆桌,P3254,getchar 来源: https://www.cnblogs.com/knife-rose/p/12095034.html