【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 }