【UVA10079 训练指南】收集者的难题【最大流】

题意:

  Bob和他的朋友从糖果包装里手机贴纸。这些朋友每人手里都有一些(可能有重复的)贴纸,并且只跟别人交换他所没有的贴纸,贴纸总是一对一交换。

 Bob比这些朋友更聪明,因为他意识到只跟别人交换自己没有的贴纸并不总是最优的。在某些情况下,换来一张重复的贴纸更划算。

 假设Bob的朋友只和Bob交换(他们之间不交换),并且这些朋友只会出让手里的重复贴纸来交换他们没有的不同贴纸。你的任务是帮助Bob算出他最终可以得到的不同贴纸的最大数量。

分析

  建n-1个点(除Bob以外的每个人)和m个点(每个物品)从s向每个物品连边,容量为拥有该物品的数量。如果某人已经至少拥有两个物品j,那么就从i向j连边,容量为拥有的物品数-1;如果没有物品j,就从j向i连边。

 

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <queue>
  6 
  7 using namespace std;
  8 const int maxn=1000+10;
  9 const int maxm=30;
 10 const int INF=2147000000;
 11 struct Dinic{
 12     int head[maxn],Next[maxn],to[maxn],cap[maxn],flow[maxn];
 13     int sz,n,m,s,t;
 14     bool vis[maxn];
 15     int cur[maxn],d[maxn];
 16     void init(int n){
 17         this->n=n;
 18         memset(head,-1,sizeof(head));
 19         this->sz=-1;
 20     }
 21     void add_edge(int a,int b,int c){
 22         ++sz;
 23         to[sz]=b;
 24         cap[sz]=c;flow[sz]=0;
 25         Next[sz]=head[a];head[a]=sz;
 26         ++sz;
 27         to[sz]=a;
 28         cap[sz]=c;flow[sz]=c;
 29         Next[sz]=head[b];head[b]=sz;
 30     }
 31     bool BFS(){
 32         memset(vis,0,sizeof(vis));
 33         queue<int>Q;
 34         vis[s]=1;
 35         d[s]=0;
 36         Q.push(s);
 37         while(!Q.empty()){
 38             int u=Q.front();Q.pop();
 39             for(int i=head[u];i!=-1;i=Next[i]){
 40                 int v=to[i];
 41                 if(!vis[v]&&cap[i]>flow[i]){
 42                     vis[v]=1;
 43                     d[v]=d[u]+1;
 44                     Q.push(v);
 45                 }
 46             }
 47         }
 48         return vis[t];
 49    }
 50     int DFS(int x,int a){
 51         if(x==t||a==0)return a;
 52         int Flow=0,f;
 53         for(int& i=cur[x];i!=-1;i=Next[i]){
 54             int v=to[i];
 55             if(d[v]==d[x]+1&&(f=DFS(v,min(a,cap[i]-flow[i])))>0){
 56                 Flow+=f;
 57                 flow[i]+=f;
 58                 flow[i^1]-=f;
 59                 a-=f;
 60                 if(a==0)break;
 61             }
 62         }
 63         return Flow;
 64     }
 65     int Maxflow(int s,int t){
 66         this->s=s,this->t=t;
 67         int Flow=0;
 68         while(BFS()){
 69             for(int i=0;i<=n;i++)
 70              cur[i]=head[i];
 71 
 72             Flow+=DFS(s,INF);
 73         }
 74         return Flow;
 75     }
 76 }dinic;
 77 int n,m,T,kase;
 78 int main(){
 79     kase=0;
 80     scanf("%d",&T);
 81     for(int t=1;t<=T;t++){
 82         ++kase;
 83         scanf("%d%d",&n,&m);
 84         dinic.init(n+m+2);
 85         int a[maxm];
 86         dinic.s=0;dinic.t=n+m+1;
 87         for(int i=1;i<=n;i++){
 88             int num;
 89             scanf("%d",&num);
 90             memset(a,0,sizeof(a));
 91             for(int j=1;j<=num;j++){
 92                 int aa;
 93                 scanf("%d",&aa);
 94                 a[aa]++;
 95             }
 96             if(i==1){
 97                 for(int j=1;j<=m;j++){
 98                     if(a[j])
 99                     dinic.add_edge(0,n+j,a[j]);
100                 }
101             }else{
102                 for(int j=1;j<=m;j++){
103                     if(a[j]>=2){
104                         dinic.add_edge(i,n+j,a[j]-1);
105                     }
106                     if(a[j]==0){
107                         dinic.add_edge(n+j,i,1);
108                     }
109                 }
110             }
111         }
112         for(int i=1;i<=m;i++)
113             dinic.add_edge(i+n,dinic.t,1);
114         int ans=dinic.Maxflow(0,dinic.t);
115         printf("Case #%d: %d\n",kase,ans);
116     }
117 return 0;
118 }
View Code

 

posted @ 2018-07-13 13:17  蒟蒻LQL  阅读(270)  评论(0编辑  收藏  举报