这题是一道网络流的题目(废话)
但是也可以用贪心做
但是这是一篇网络流的题解
所以咱们正常一点
首先将源点向每一个单位连一条流量为人数的边~
然后将每一张桌子向汇点连一条流量为桌子容量的边~
最终将每一个单位向每一张桌子连一条流量为1的边~
然后跑最大流(废话)
对比最大流和总人数~
如果相等,成功!
否则,失败!
至于输出方案,枚举每个单位向桌子连的边是否有流量即可。
代码:
#include<bits/stdc++.h>
#define o edge[i].t
using namespace std;
int n,m,S,T=23333,sum,cnt=1;
int dep[66666],head[66666];
struct hh{int t,w,nxt;}edge[666666];
void make_edge(int f,int t,int w)
{
edge[++cnt]=(hh){t,w,head[f]};
head[f]=cnt;
edge[++cnt]=(hh){f,0,head[t]};
head[t]=cnt;
return;
}
void build()
{
int x;
for (int i=1;i<=n;i++) scanf("%d",&x),sum+=x,make_edge(S,i,x);
for (int i=1;i<=m;i++) scanf("%d",&x),make_edge(i+n,T,x);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
make_edge(i,j+n,1);
return;
}
int dfs(int x,int num)
{
if (x==T) return num;
int ret=0;
for (int i=head[x];i;i=edge[i].nxt)
if (dep[o]==dep[x]+1&&edge[i].w)
{
int k=dfs(o,min(num,edge[i].w));
num-=k;
ret+=k;
edge[i].w-=k;
edge[i^1].w+=k;
if (!num) break;
}
if (!ret) dep[x]=0;
return ret;
}
bool bfs()
{
queue<int>q;
q.push(S);
memset(dep,0,sizeof(dep));
dep[S]=1;
while (!q.empty())
{
int tmp=q.front();
q.pop();
for (int i=head[tmp];i;i=edge[i].nxt)
if (!dep[o]&&edge[i].w)
{
dep[o]=dep[tmp]+1;
q.push(o);
}
}
return dep[T];
}
void dinic()
{
while (bfs()) sum-=dfs(S,0x7fffffff);
return;
}
void in()
{
scanf("%d %d",&n,&m);
return;
}
void out()
{
if (sum){printf("0");return;}
printf("1\n");
for (int i=1;i<=n;i++)
{
for (int j=head[i];j;j=edge[j].nxt)
if (!edge[j].w&&edge[j].t!=S)//有流量,边终点不是源点
printf("%d ",edge[j].t-n);
puts("");
}
return;
}
int main()
{
in();
build();
dinic();
out();
return 0;
}