题目描述
假设有来自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 个方案。
样例输入:
4 5
4 5 3 5
3 5 2 6 4
样例输出:
1
1 2 4 5
1 2 3 4 5
2 4 5
1 2 3 4 5
本题可以用贪心求解。
首先将桌子从大到小排个序,再讲单位的规模从大到小排个序。单位规模越大就越难满足,所以我们优先考虑单位。
之后先坐大桌子,再坐小桌子就OK了。
但是此题我写的网络流
模型很简单,二分图最大匹配,桌子和单位匹配一下。
建立二分图,每个单位为X集合中的顶点,每个餐桌为Y集合中的顶点,增设附加源S和汇T。
1、从S向每个Xi顶点连接一条容量为该单位人数的有向边。
2、从每个Yi顶点向T连接一条容量为该餐桌容量的有向边。
3、X集合中每个顶点向Y集合中每个顶点连接一条容量为1的有向边。
之后跑最大流。
#include<cstdio> #include<algorithm> #include<cstring> #include<queue> using namespace std; #define N 4000000 int n,m; int a[N]; int b[N]; int nex[N]; int head[N]; int to[N]; int val[N]; int dep[N]; int S,T; int idx=1; void addedge(int a,int b,int c) { nex[++idx]=head[a]; head[a]=idx; to[idx]=b; val[idx]=c; } bool bfs(int S,int T) { memset(dep,-1,sizeof(dep)); queue <int > q; q.push(S); dep[S]=0; while(!q.empty()) { int x=q.front(); q.pop(); for(int i=head[x];i;i=nex[i]) { if(val[i]&&dep[to[i]]==-1) { dep[to[i]]=dep[x]+1; q.push(to[i]); if(to[i]==T) return 1; } } } return 0; } int dinic(int x,int flow) { int nowflow=flow; if(x==T) return nowflow; for(int i=head[x];i;i=nex[i]) { if(val[i]>0&&dep[to[i]]==dep[x]+1) { int now=dinic(to[i],min(nowflow,val[i])); if(now==0) dep[to[i]]=-1; nowflow-=now; val[i]-=now; val[i^1]+=now; if(nowflow==0) break; } } return flow-nowflow; } int main() { scanf("%d%d",&n,&m); S=0; T=n+m+1; int sum=0; for(int i=1;i<=n;i++) { scanf("%d",&a[i]); sum+=a[i]; addedge(S,i,a[i]); addedge(i,S,0); } for(int i=n+1;i<=m+n;i++) { scanf("%d",&b[i]); addedge(i,T,b[i]); addedge(T,i,0); } for(int i=1;i<=n;i++) for(int j=n+1;j<=m+n;j++) { addedge(i,j,1); addedge(j,i,0); } int ans=0; while(bfs(S,T)) ans+=dinic(S,1<<30); if(ans==0||ans<sum) printf("0"); else { puts("1"); for(int i=1;i<=n;i++) { for(int j=head[i];j;j=nex[j]) { if(to[j]!=S&&(!val[j])) printf("%d ",to[j]-n); } puts(""); } } }