题目链接:https://www.luogu.org/problemnew/show/P3254
题目描述
假设有来自m 个不同单位的代表参加一次国际会议。每个单位的代表数分别为ri (i =1,2,……,m)。
会议餐厅共有n 张餐桌,每张餐桌可容纳ci (i =1,2,……,n)个代表就餐。
为了使代表们充分交流,希望从同一个单位来的代表不在同一个餐桌就餐。试设计一个算法,给出满足要求的代表就餐方案。
对于给定的代表数和餐桌数以及餐桌容量,编程计算满足要求的代表就餐方案。
输入输出格式
输入格式:
第1 行有2 个正整数m 和n,m 表示单位数,n 表示餐桌数,1<=m<=150, 1<=n<=270。
第2 行有m 个正整数,分别表示每个单位的代表数。
第3 行有n 个正整数,分别表示每个餐桌的容量。
输出格式:
如果问题有解,第1 行输出1,否则输出0。接下来的m 行给出每个单位代表的就餐桌号。如果有多个满足要求的方案,只要输出1 个方案。
输入输出样例
输入样例#1: 复制
4 5 4 5 3 5 3 5 2 6 4
输出样例#1: 复制
1 1 2 4 5 1 2 3 4 5 2 4 5 1 2 3 4 5
思路:
1~n 为代表,n+1 ~ n+m 为桌子
1.添加源点s和汇点t
2.添加s到1~n每个点容量为ai 的边
3.添加n+1~n+m 每个点到t 容量为bi 的边
4.添加1~n 每个点 到 n+1 ~n+m 每个点容量 为1的边
5.用最大流跑二分图,如果每个流都满流,说明有可行方案,不然就输出0
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define inf 0x3fffffff
using namespace std;
const int maxn=1000, maxm=1e6+7;
int first[maxn],sign,cur[maxn];
int s,t,d[maxn];
int mp[maxn][maxn];
vector<int > vec[300];
struct node{
int to,w,next;
}edge[maxm];
void init(){
memset(first,-1,sizeof(first));
sign=0;
}
void add_edge(int u,int v,int w){
edge[sign].to=v;
edge[sign].w=w;
edge[sign].next=first[u];
first[u]=sign++;
edge[sign].to=u;
edge[sign].w=0;
edge[sign].next=first[v];
first[v]=sign++;
}
int bfs(){
queue<int>q;
memset(d,0,sizeof(d));
d[s]=1;
q.push(s);
while(!q.empty()){
int top=q.front();
q.pop();
for(int i=first[top];~i;i=edge[i].next){
int to=edge[i].to;
if(edge[i].w>0&&d[to]==0){
d[to]=d[top]+1;
if(to==t)
return 1;
q.push(to);
}
}
}
return d[t]!=0;
}
int dfs(int top,int flow){
if(top==t)
return flow;
int ans=0,x=0;
for(int i=cur[top];~i;i=edge[i].next){
int to=edge[i].to;
if(edge[i].w>0&&d[to]==d[top]+1){
x=dfs(to,min(flow-ans,edge[i].w));
edge[i].w-=x;
edge[i^1].w+=x;
if(edge[i].w)
cur[top] = i;
ans+=x;
if(ans==flow)
return flow;
}
}
if(ans==0)
d[top]=0;
return ans;
}
int dinic(int n){
int ans=0;
while(bfs()){
for(int i=0;i<=n;i++)
cur[i]=first[i];
ans+=dfs(s,inf);
}
return ans;
}
int peo[1007], tab;
int main(){
int n, m, sum=0;
scanf("%d%d", &n, &m);
init();
s=0,t=n+m+1;
for(int i=1; i<=n; ++i){
scanf("%d", &tab);
sum += tab;
add_edge(s, i, tab);
}
for(int i=1; i<=n; ++i)
for(int j=n+1; j<=m+n; ++j)
add_edge(i, j, 1);
for(int i=n+1; i<=m+n; ++i){
scanf("%d", &tab);
add_edge(i, t, tab);
}
int ans=dinic(t);
if(ans == sum)
{
printf("1\n");
for(int i = n +1 ;i <= n + m ;i ++)
{
for(int j = first[i];~j;j = edge[j].next)
{
if(edge[j].w == 1 && edge[j].to != t)
{
vec[edge[j].to].push_back(i - n);
}
}
}
for(int i = 1;i <= n;i ++)
{
printf("%d",vec[i][0]);
for(int j = 1;j < vec[i].size();j ++)
{
printf(" %d",vec[i][j]);
}
printf("\n");
}
}
else
{
puts("0\n");
}
return 0;
}