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

题目大意:有n个人,已知每人有ki个糖纸,并且知道每张糖纸的颜色。其中,Bob希望能和同伴交换使得手上的糖纸数尽量多。他的同伴只会用手上的重复的交换手上没有的,并且他的同伴们之间不会产生交换。求出Bob能拥有的最大糖纸种数。

题目分析:对于Bob拥有的糖纸,从源点s连一条弧,容量为Bob拥有的数量;对于Bob的小伙伴,从Bob连一条弧向他拥有的糖纸,容量为拥有数量减1,对于他不拥有的糖纸,连一条有向弧从糖纸到他,容量为1;对于每一种糖纸,连一条弧向汇点t。最大流便是答案。

代码如下:

# include<iostream>
# include<cstdio>
# include<cmath>
# include<string>
# include<vector>
# include<list>
# include<set>
# include<map>
# include<queue>
# include<cstring>
# include<algorithm>
using namespace std;

# define LL long long
# define REP(i,s,n) for(int i=s;i<n;++i)
# define CL(a,b) memset(a,b,sizeof(a))
# define CLL(a,b,n) fill(a,a+n,b)

const double inf=1e30;
const int INF=1<<30;
const int N=80;

struct Edge
{
    int fr,to,cap,fw;
    Edge(int _fr,int _to,int _cap,int _fw):fr(_fr),to(_to),cap(_cap),fw(_fw){}
};
vector<Edge>edges;
vector<int>G[N];
int vis[N],d[N],cur[N],s,t,n,m,mark[30];

void init()
{
    s=0,t=n+m+1;
    edges.clear();
    REP(i,0,t+1) G[i].clear();
}

void addEdge(int u,int v,int cap)
{
    edges.push_back(Edge(u,v,cap,0));
    edges.push_back(Edge(v,u,0,0));
    int len=edges.size();
    G[u].push_back(len-2);
    G[v].push_back(len-1);
}

bool BFS()
{
    queue<int>q;
    CL(vis,0);
    d[s]=0;
    vis[s]=1;
    q.push(s);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        REP(i,0,G[x].size()){
            Edge &e=edges[G[x][i]];
            if(!vis[e.to]&&e.cap>e.fw){
                vis[e.to]=1;
                d[e.to]=d[x]+1;
                q.push(e.to);
            }
        }
    }
    return vis[t];
}

int DFS(int x,int a)
{
    if(x==t||a==0) return a;
    int flow=0,f;
    for(int &i=cur[x];i<G[x].size();++i){
        Edge &e=edges[G[x][i]];
        if(d[e.to]==d[x]+1&&(f=DFS(e.to,min(a,e.cap-e.fw)))>0){
            e.fw+=f;
            edges[G[x][i]^1].fw-=f;
            flow+=f;
            a-=f;
            if(a==0) break;
        }
    }
    return flow;
}

int Dinic()
{
    int flow=0;
    while(BFS()){
        CL(cur,0);
        flow+=DFS(s,INF);
    }
    return flow;
}

int main()
{
    int T,k,r,cas=0;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        init();
        CL(mark,0);
        scanf("%d",&k);
        while(k--)
        {
            scanf("%d",&r);
            ++mark[r];
        }
        REP(i,1,m+1) if(mark[i]) addEdge(s,i,mark[i]);
        REP(i,1,n){
            CL(mark,0);
            scanf("%d",&k);
            while(k--){
                scanf("%d",&r);
                ++mark[r];
            }
            REP(j,1,m+1){
                if(mark[j]>=2) addEdge(m+i+1,j,mark[j]-1);
                else if(mark[j]==0) addEdge(j,m+i+1,1);
            }
        }
        REP(i,1,m+1) addEdge(i,t,1);
        printf("Case #%d: %d\n",++cas,Dinic());
    }
  return 0;
}

  

时间: 2024-12-19 15:16:58

UVA-10779 Collectors Problem (网络流建模)的相关文章

UVA 10779 Collectors Problem 网络流+建图

题目链接:点击打开链接 题意:白书P370 思路: 因为问的是最后贴纸总数,那么就设最后的贴纸总数是网络流的答案. 首先我们模拟贴纸的流动过程: Bob 的 某种贴纸a -> 给一个没有a贴纸的人Peo -> 还给Bob一个Peo的某张重复贴纸 -> 这张贴纸可以算作答案了 #include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> #include

UVA 10779 - Collectors Problem(网络流)

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

UVA 10779 Collectors Problem[最大流]

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

uva 10779 Collectors Problem

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

UVA 10779 (最大流)

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=33631 题目大意:Bob有一些贴纸,他可以和别人交换,他可以把自己独有的贴纸拿出去,也可以把重复的贴纸拿出去(有时候把独有的贴纸而不是重复的贴纸拿出去能换到更多贴纸). Bob的朋友也有一些贴纸,但是他们只会拿自己重复的贴纸和Bob换,而且换的是自己没有的贴纸. 求Bob最后最多能有多少种贴纸. 解题思路: 题目意思很明确了.就算把重复的贴纸拿出去也不一定最优,贪

UVALive-3268 Jamie&#39;s Contact Groups (最大流,网络流建模)

题目大意:你的手机通讯录里有n个联系人,m个分组,其中,有的联系人在多个分组里.你的任务是在一些分组里删除一些联系人,使得每个联系人只在一个分组里并且使人数最多的那个分组人数最少.找出人数最多的那个分组中的人数. 题目分析:要求的是最小的最大值,二分枚举这个最小的最大人数x.增加源点s和汇点t,从s向每一个联系人连一条弧,容量为1,表示一个联系人只能在一个分组中:然后对于每个联系人向他所在的分组连一条弧,容量为1,表示在这个分组里最多保存一次该联系人:然后从每个分组向汇点连一条弧,容量为x,表示

HDU 4975 A simple Gaussian elimination problem. 网络流+矩阵上的dp

随机输出保平安啊 和hdu4888一个意思,先跑个网络流然后dp判可行. ==n^3的dp过不了,所以把n改成200. ==因为出题人没有把多解的情况放在200*200以外的矩阵. #include <cstdio> #include <cstring> #include <vector> #include <queue> #include <algorithm> using namespace std; const int MAX_N = 12

网络流建模总结

各大竞赛中不乏有许多网络流建模的题,而对于像我(= =)这样的蒟蒻来说可谓是一道题一种解法,还是”老题随便A,新题永不会“的态度,故开此帖来总结一些网络流建模的模型吧,不断更新. 1.分配问题:顾名思义,将一个集合分解为若干个小集合的题目. 常见套话:"现在我们有一批物资要通过一些道路运往某地...","每一场比赛可以为总比分提供两分,可以是每队一分(平局),或者是2-0(一队胜出)...","一块蛋糕,现在有n个厨师来了,每人可以切几份..."

uva 11991 Easy Problem from Rujia Liu? Data Structure

// uva 11991 Easy Problem from Rujia Liu? // 给一个包含n个数的数组,需要回答若干个询问,每次询问两个整数 // k和v,输出从左到右第k个v的下标 // // 本题因为n比较大,所以直接开二维数组是不现实的 // 如果直接用vector的话,也是会有大量的浪费 // 所以可以先离散化一下,找到一共有多少个不同的数 // 再用vector动态数组就可以搞定了 // // 看着书上的map写的挺精彩的,我就习用了下来 // // 非常精彩,继续练吧...

uva 11991 - Easy Problem from Rujia Liu?(STL)

题目链接:uva 11991 - Easy Problem from Rujia Liu? 题目大意:给出一个包含n个整数的数组,你需要回答若干询问,每次询问两个整数k和v,输出从左到右第k个v的下标 解题思路:用map映射一个vector,对应即为map<int>即为一个可变长的数组,读取数组的时候将对应值放入即可. #include <cstdio> #include <cstring> #include <map> #include <vecto