UVA10779 Collectors Problem

题目链接:https://cn.vjudge.net/problem/UVA-10779

前言:

  本题是关于姜志豪《网络流的一些建模方法》的笔记。

知识点:  最大流

题意摘抄:

  \(Bob\) 和他的朋友从糖果包装里收集贴纸。\(Bob\) 和他的朋友总共 \(n\) 人。共有 \(m\) 种不同的贴纸。

  每人手里都有一些(可能有重复的)贴纸,并且只跟别人交换他所没有的贴纸。贴纸总是一对一交换。

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

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

  \((2 \le n le 10, 5 \le m \le 25)\)

解题思路:

  每种贴纸、每个朋友都各视为一个点,再加上一个源点和一个汇点。

  对于每种贴纸,建一条从源点到这种贴纸的边,容量为 \(Bob\) 所拥有的这种贴纸的张数;

  对于每一个朋友,如果他没有某种贴纸,就建一条从这种贴纸到他的边,容量为 \(1\);如果他有这种贴纸并且拥有量 \(k\) 大于\(1\) ,则建一条从他到这种贴纸的边,容量为 \(k-1\).

  对于每种贴纸,再建一条边到汇点,容量为 \(1\).

AC代码:

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 const int MAXN = 510;//点数的最大值
  4 const int MAXM = 15000;//边数的最大值
  5 const int INF = 0x3f3f3f3f;
  6 
  7 struct Edge{
  8     int to,next,cap,flow;
  9 }edge[MAXM];//注意是MAXM
 10 int tol;
 11 int head[MAXN];
 12 int gap[MAXN],dep[MAXN],cur[MAXN];
 13 void init(){
 14     tol = 0;
 15     memset(head,-1,sizeof(head));
 16 }
 17 void addedge(int u,int v,int w,int rw = 0){
 18     edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0;
 19     edge[tol].next = head[u]; head[u] = tol++;
 20     edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0;
 21     edge[tol].next = head[v]; head[v] = tol++;
 22 }
 23 int Q[MAXN];
 24 void BFS(int start,int end){
 25     memset(dep,-1,sizeof(dep));
 26     memset(gap,0,sizeof(gap));
 27     gap[0] = 1;
 28     int front = 0, rear = 0;
 29     dep[end] = 0;
 30     Q[rear++] = end;
 31     while(front != rear){
 32         int u = Q[front++];
 33         for(int i = head[u]; i != -1; i = edge[i].next){
 34             int v = edge[i].to;
 35             if(dep[v] != -1)
 36                 continue;
 37             Q[rear++] = v;
 38             dep[v] = dep[u] + 1;
 39             gap[dep[v]]++;
 40         }
 41     }
 42 }
 43 int S[MAXN];
 44 int sap(int start,int end,int N){
 45     BFS(start,end);
 46     memcpy(cur,head,sizeof(head));
 47     int top = 0;
 48     int u = start;
 49     int ans = 0;
 50     while(dep[start] < N){
 51         if(u == end){
 52             int Min = INF;
 53             int inser;
 54             for(int i = 0;i < top;i++)
 55                 if(Min > edge[S[i]].cap - edge[S[i]].flow){
 56                     Min = edge[S[i]].cap - edge[S[i]].flow;
 57                     inser = i;
 58                 }
 59             for(int i = 0;i < top;i++){
 60                 edge[S[i]].flow += Min;
 61                 edge[S[i]^1].flow -= Min;
 62             }
 63             ans += Min;
 64             top = inser;
 65             u = edge[S[top]^1].to;
 66             continue;
 67         }
 68         bool flag = false;
 69         int v;
 70         for(int i = cur[u]; i != -1; i = edge[i].next){
 71             v = edge[i].to;
 72             if(edge[i].cap - edge[i].flow && dep[v]+1 == dep[u]){
 73                 flag = true;
 74                 cur[u] = i;
 75                 break;
 76             }
 77         }
 78         if(flag){
 79             S[top++] = cur[u];
 80             u = v;
 81             continue;
 82         }
 83         int Min = N;
 84         for(int i = head[u]; i != -1; i = edge[i].next)
 85             if(edge[i].cap - edge[i].flow && dep[edge[i].to] < Min){
 86                 Min = dep[edge[i].to];
 87                 cur[u] = i;
 88             }
 89         gap[dep[u]]--;
 90         if(!gap[dep[u]])
 91             return ans;
 92         dep[u] = Min + 1;
 93         gap[dep[u]]++;
 94         if(u != start)
 95             u = edge[S[--top]^1].to;
 96     }
 97     return ans;
 98 }
 99 int has[30];
100 int main(){
101     int T;
102     int n,m,k;
103     int num;
104     int kase=1;
105     scanf("%d",&T);
106     while(T--){
107         init();
108         int s=0,t=MAXN-1;
109         memset(has,0,sizeof(has));
110         scanf("%d%d",&n,&m);
111         scanf("%d",&k);
112         while(k--){
113             scanf("%d",&num);
114             has[num]++;
115         }
116         for(int i=1;i<=m;i++){
117             addedge(s,i,has[i]);
118             addedge(i,t,1);
119         }
120         for(int i=1;i<n;i++){
121             memset(has,0,sizeof(has));
122             scanf("%d",&k);
123             while(k--){
124                 scanf("%d",&num);
125                 has[num]++;
126             }
127             for(int j=1;j<=m;j++){
128                 if(!has[j])
129                     addedge(j,30+i,1);
130                 else if(has[j]>1)
131                     addedge(30+i,j,has[j]-1);
132             }
133         }
134         printf("Case #%d: %d\n",kase++,sap(s,t,2+m+n));
135     }
136     return 0;
137 }

猜你喜欢

转载自www.cnblogs.com/Blogggggg/p/9061363.html