1. 程式人生 > >BZOJ 1711 吃飯dining/Luogu P1402 酒店之王 拆點+最大流流匹配

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
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,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 }
吃飯dining
 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 }
酒店之王