BZOJ 1711 吃飯dining/Luogu P1402 酒店之王 拆點+最大流流匹配
題意:
(吃飯dining)有F種食物和D種飲料,每種食物或飲料只能供一頭牛享用,且每頭牛隻享用一種食物和一種飲料。現在有n頭牛,每頭牛都有自己喜歡的食物種類列表和飲料種類列表,問最多能使幾頭牛同時享用到自己喜歡的食物和飲料。(1 <= f <= 100, 1 <= d <= 100, 1 <= n <= 100)
(酒店之王)XX酒店的老闆想成為酒店之王,本著這種希望,第一步要將酒店變得人性化。由於很多來住店的旅客有自己喜好的房間色調、陽光等,也有自己所愛的菜,但是該酒店只有p間房間,一天只有固定的q道不同的菜。
有一天來了n個客人,每個客人說出了自己喜歡哪些房間,喜歡哪道菜。但是很不幸,可能做不到讓所有顧客滿意(滿意的條件是住進喜歡的房間,吃到喜歡的菜)。
這裡要怎麼分配,能使最多顧客滿意呢?
分析:
我們想想發現,這兩道題並沒什麼不同,都是一些人,一些東西,分別喜歡兩類東西中的一些,每人只能佔有兩類中的各一樣東西,問如何安排,讓更多的人滿意。
倘若只有一類東西,也許我們會想到二分圖匹配。
但是兩樣東西,建二分圖我們是建不出來的,所以只能藉由網路流來解決匹配問題,我們依舊是考慮題目中的限制問題:
首先限制1.喜歡兩類東西中的各一些。
限制2.每人只能在兩類中各佔有一樣東西。
我們發現限制不多,所以建圖也沒那麼複雜。我們一單位的流量當然是代表一樣東西。
我們怎麼建出滿足限制2的圖?
引出一個拆點技巧,我們將人拆成兩個點,我們保證這兩個點之間的流量最大是1,所以一個人最多選一樣東西。
所以我們把圖簡稱這樣:
圖醜請不要在意這些細節2333
藍色的點代表人,橙色代表第一類物品,紫色代表第二類物品,邊容量都是1.
只不過源點向第一類物品連邊,第一類物品向喜歡它的人的一號店連邊,人的一號點向二號點連邊,人的二號點向他喜歡的第二類物品連邊,第二類物品向匯點連邊即可。這樣,一單位流量流經一個人的兩個點,代表被這個人選擇了。
兩道題幾乎一模一樣,都不用改資料範圍,改改主函式就好了
程式碼:
1 #include<bits/stdc++.h> 2 #define ms(a,x) memset(a,x,sizeof(a)) 3吃飯diningusing namespace std;int tot=0; 4 const int N=10005,inf=0x3f3f3f3f; 5 struct node{int y,z,nxt;}e[N*2]; 6 int S,T,q[N],h[N],c=1,n,m,k,d[N]; 7 int c1[N],ho[N],di[N],c2[N]; 8 int add(int x,int y,int z){ 9 e[++c]=(node){y,z,h[x]};h[x]=c; 10 e[++c]=(node){x,0,h[y]};h[y]=c; 11 } bool bfs(){ 12 int f=1,t=0;ms(d,-1); 13 q[++t]=S;d[S]=0; 14 while(f<=t){ 15 int x=q[f++]; 16 for(int i=h[x],y;i;i=e[i].nxt) 17 if(d[y=e[i].y]==-1&&e[i].z) 18 d[y]=d[x]+1,q[++t]=y; 19 } return (d[T]!=-1); 20 } int dfs(int x,int f){ 21 if(x==T) return f;int w,tmp=0; 22 for(int i=h[x],y;i;i=e[i].nxt) 23 if(d[y=e[i].y]==d[x]+1&&e[i].z){ 24 w=dfs(y,min(e[i].z,f-tmp)); 25 if(!w) d[y]=-1; 26 e[i].z-=w;e[i^1].z+=w; 27 tmp+=w;if(tmp==f) return f; 28 } return tmp; 29 } void dinic(){ 30 while(bfs()) tot+=dfs(S,inf); 31 } int main(){ 32 scanf("%d%d%d",&n,&m,&k); 33 S=0,T=n*2+m+k+1; 34 for(int i=1;i<=m;i++) ho[i]=i; 35 for(int i=1;i<=n;i++) c1[i]=i+m; 36 for(int i=1;i<=k;i++) di[i]=n+m+i; 37 for(int i=1;i<=n;i++) c2[i]=n+m+k+i; 38 for(int i=1;i<=m;i++) add(S,ho[i],1); 39 for(int i=1;i<=k;i++) add(di[i],T,1); 40 for(int i=1;i<=n;i++) add(c1[i],c2[i],1); 41 for(int i=1,u,v;i<=n;i++){ 42 scanf("%d%d",&u,&v); 43 for(int j=1,p;j<=u;j++) 44 scanf("%d",&p),add(ho[p],c1[i],1); 45 for(int j=1,p;j<=v;j++) 46 scanf("%d",&p),add(c2[i],di[p],1); 47 } dinic();printf("%d\n",tot);return 0; 48 }
1 #include<bits/stdc++.h> 2 #define ms(a,x) memset(a,x,sizeof(a)) 3 using namespace std;int tot=0; 4 const int N=10005,inf=0x3f3f3f3f; 5 struct node{int y,z,nxt;}e[N*2]; 6 int S,T,q[N],h[N],c=1,n,m,k,d[N]; 7 int c1[N],ho[N],di[N],c2[N]; 8 int add(int x,int y,int z){ 9 e[++c]=(node){y,z,h[x]};h[x]=c; 10 e[++c]=(node){x,0,h[y]};h[y]=c; 11 } bool bfs(){ 12 int f=1,t=0;ms(d,-1); 13 q[++t]=S;d[S]=0; 14 while(f<=t){ 15 int x=q[f++]; 16 for(int i=h[x],y;i;i=e[i].nxt) 17 if(d[y=e[i].y]==-1&&e[i].z) 18 d[y]=d[x]+1,q[++t]=y; 19 } return (d[T]!=-1); 20 } int dfs(int x,int f){ 21 if(x==T) return f;int w,tmp=0; 22 for(int i=h[x],y;i;i=e[i].nxt) 23 if(d[y=e[i].y]==d[x]+1&&e[i].z){ 24 w=dfs(y,min(e[i].z,f-tmp)); 25 if(!w) d[y]=-1; 26 e[i].z-=w;e[i^1].z+=w; 27 tmp+=w;if(tmp==f) return f; 28 } return tmp; 29 } void dinic(){ 30 while(bfs()) tot+=dfs(S,inf); 31 } int main(){ 32 scanf("%d%d%d",&n,&m,&k); 33 S=0,T=n*2+m+k+1; 34 for(int i=1;i<=m;i++) ho[i]=i; 35 for(int i=1;i<=n;i++) c1[i]=i+m; 36 for(int i=1;i<=k;i++) di[i]=n+m+i; 37 for(int i=1;i<=n;i++) c2[i]=n+m+k+i; 38 for(int i=1;i<=m;i++) add(S,ho[i],1); 39 for(int i=1;i<=k;i++) add(di[i],T,1); 40 for(int i=1;i<=n;i++) add(c1[i],c2[i],1); 41 for(int i=1;i<=n;i++) 42 for(int j=1,p;j<=m;j++) 43 scanf("%1d",&p),p?add(ho[j],c1[i],1):0; 44 for(int i=1;i<=n;i++) 45 for(int j=1,p;j<=k;j++) 46 scanf("%1d",&p),p?add(c2[i],di[j],1):0; 47 dinic();printf("%d\n",tot);return 0; 48 }酒店之王