UVa10779 Collectors Problem(最大流)

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=33631

【思路】

最大流。

构图:

1  建立m个x点表示贴纸,n-1个y点表示Bob的朋友,ST表示源汇点。

2  S向x[j]连一条容量为sum[0][j]的边,表示Bob可以换出如是贴纸。

3  y[j]向x[i]连容量为1的边当且仅当i没有j,x[i]向y[j]连容量为sum[i][j]-1的边。

   4  x[i]向T连一条容量为1的边统计不同种类的数目。

【代码】

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

UVa10779 Collectors Problem(最大流)的相关文章

UVA 10779 Collectors Problem[最大流]

from:neopenx 题目大意:Bob有一些贴纸,他可以和别人交换,他可以把自己独有的贴纸拿出去,也可以把重复的贴纸拿出去(有时候把独有的贴纸而不是重复的贴纸拿出去能换到更多贴纸). Bob的朋友也有一些贴纸,但是他们只会拿自己重复的贴纸和Bob换,而且换的是自己没有的贴纸. 求Bob最后最多能有多少种贴纸. 解题思路: 题目意思很明确了.就算把重复的贴纸拿出去也不一定最优,贪心就不用尝试了. 全局资源调配得使用网络流模型. 建图方式: ①S点(看作是Bob)->所有物品:连一条边,cap是

UVA-10779 Collectors Problem (网络流建模)

题目大意:有n个人,已知每人有ki个糖纸,并且知道每张糖纸的颜色.其中,Bob希望能和同伴交换使得手上的糖纸数尽量多.他的同伴只会用手上的重复的交换手上没有的,并且他的同伴们之间不会产生交换.求出Bob能拥有的最大糖纸种数. 题目分析:对于Bob拥有的糖纸,从源点s连一条弧,容量为Bob拥有的数量:对于Bob的小伙伴,从Bob连一条弧向他拥有的糖纸,容量为拥有数量减1,对于他不拥有的糖纸,连一条有向弧从糖纸到他,容量为1:对于每一种糖纸,连一条弧向汇点t.最大流便是答案. 代码如下: # inc

UVA 10779 - Collectors Problem(网络流)

UVA 10779 - Collectors Problem 题目链接 题意:每个人有一种贴图,现在第0个人要去和别人交换贴图,来保证自己的贴图尽量多,只有别人没有该种贴图,并且自己有2张以上另一种贴图才会换,问最多有几张贴图 思路:最大流,关键在于如何建模,把0号人和物品连边,容量为有的容量,然后其他人如果物品等于0的,连一条边从物品到这个人,表示能交换,然后如果物品大于1的,连一条边从这个人到物品,容量为物品减1(自己要留一个),然后把所有物品连到汇点,跑一次最大流即可 代码: #inclu

HDU 3549 Flow Problem ( 最大流 -EK 算法)

C++,G++的读取速度差距也太大了 Flow Problem 题意:n,m表示n个点m条有向带权边 问:从1-n最大流多少 裸最大流,拿来练手,挺不错的 #include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <queue> #include <algorithm> const int N = 210; #define

HDU 3549 Flow Problem (最大流)

链接:click here 题意:Network flow is a well-known difficult problem for ACMers. Given a graph, your task is to find out the maximum flow for the weighted directed graph. 翻译:网络流量是一个众所周知的难题ACMers.给定一个图,你的任务是找出加权有向图的最大流. 输出格式: Case 1: 1 Case 2: 2 思路:跟hdu153

Collectors Problem

https://vjudge.net/problem/UVA-10779#author=0 网络流 1.Bob向他有的贴纸连边,流量为他有的贴纸数量 2.每一种贴纸向汇点连流量为1的边 3.其余人,如果没贴纸i,由i向这个人连一条流量为1的边 4.如果贴纸i数量>1,由这个人向i连一条流量为数量-1的边 #include <cstdio> #include <algorithm> #include <queue> using namespace std; cons

hdu 4975 A simple Gaussian elimination problem 最大流+找环

原题链接 http://acm.hdu.edu.cn/showproblem.php?pid=4975 这是一道很裸的最大流,将每个点(i,j)看作是从Ri向Cj的一条容量为9的边,从源点除法连接每个Ri,再从每个Ci连接至汇点.如若最大流不是滿流,则问题无解.这道题的关键就是在于如何判断是否有多解.考虑这样一个事实,若残余网络上有多个点构成一个环,那么流量可在这个环上调整,某条边上多余的流量可以被环上的其他的边弥补回来.所以如果残余网络上存在一个边数大于2的环,那么问题则是多解.我判断是否有环

zoj3362 Beer Problem费用流

费用流 双向边 (u,v,f,c)  拆分成4条边 (u,v,f,c)  (v,u,0,-c)  (v,u,f,c)  (u,v,0,-c) 建立城市->汇点(u,T,inf,-price) #include <iostream> #include <string.h> #include <stdio.h> #include <algorithm> #include <queue> #define V 800+10 #define E 80

uva 10779 Collectors Problem

题目描述: Bob和他的朋友从糖果包装里收集贴纸.Bob和他的朋友总共n人.共有m种不同的贴纸.每人手里都有一些(可能有重复的)贴纸,并且只跟别人交换他所没有的贴纸.贴纸总是一对一交换.Bob比这些朋友更聪明,因为他意识到只跟别人交换自己没有的贴纸并不总是最优的.在某些情况下,换来一张重复的贴纸更划算.假设Bob的朋友只跟Bob交换(他们之间不交换),并且这些朋友只会出让手里的重复贴纸来交换他们没有的不同贴纸.你的任务是帮助Bob算出他最终可以得到的不同贴纸的最大数量.2 ≤ n ≤ 10, 5