網路流24題之圓桌問題
阿新 • • 發佈:2018-11-10
題目描述
假設有來自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(""); } } }