UVA 10779 (最大流)

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

题目大意:Bob有一些贴纸,他可以和别人交换,他可以把自己独有的贴纸拿出去,也可以把重复的贴纸拿出去(有时候把独有的贴纸而不是重复的贴纸拿出去能换到更多贴纸)。

Bob的朋友也有一些贴纸,但是他们只会拿自己重复的贴纸和Bob换,而且换的是自己没有的贴纸。

求Bob最后最多能有多少种贴纸。

解题思路

题目意思很明确了。就算把重复的贴纸拿出去也不一定最优,贪心就不用尝试了。

全局资源调配得使用网络流模型。

建图方式:

①S点(看作是Bob)->所有物品:连一条边,cap是Bob持有贴纸数量。

②:所有朋友->所有物品:如果这个人持有的该贴纸数量>=2,连一条边,cap是贴纸数量-1。(原因是这些人只会把重复的贴纸拿出去)。

③:所有物品->所有朋友:如果这个人没有改物品,连一条边,cap=1,。(原因是这些人会接受自己没有的贴纸)

④:所有物品->T点:连一条边,cap=1,统计物品的种类。

这样建图之后,所有物品可以看作Bob的总资产,这个总资产可以流进,也可以流出,在这基础上做一次最大流,就是结果了。

代码使用比较坑爹的边表,虽然速度不如链式前向星,但是ISAP+gap优化+当前弧优化已经足够快了。

#include "cstdio"
#include "vector"
#include "cstring"
#include "queue"
using namespace std;
#define maxn 405
#define inf 100000000
struct Edge
{
    int from,to,cap,flow;
    Edge(int FROM,int TO,int CAP,int FLOW):from(FROM),to(TO),cap(CAP),flow(FLOW) {}
};
int d[maxn],p[maxn],gap[maxn],cur[maxn],paste[15][30];
bool vis[maxn];
vector<int> G[maxn];
vector<Edge> edges;
void addedge(int from,int to,int cap)
{
    edges.push_back(Edge(from,to,cap,0));
    edges.push_back(Edge(to,from,0,0));
    int m=edges.size();
    G[from].push_back(m-2);
    G[to].push_back(m-1);
}
void bfs(int s,int t)
{
    memset(vis,false,sizeof(vis));
    memset(d,0,sizeof(d));
    memset(p,0,sizeof(p));
    d[t]=0;vis[t]=true;
    queue<int> Q;Q.push(t);
    while(!Q.empty())
    {
        int u=Q.front();Q.pop();
        for(int v=0;v<G[u].size();v++)
        {
            Edge e=edges[G[u][v]^1];
            if(!vis[e.from]&&e.cap>e.flow)
            {
                vis[e.from]=true;
                d[e.from]=d[u]+1;
                Q.push(e.from);
            }
        }
    }
}
int augment(int s,int t)
{
    int x=t,a=inf;
    while(x!=s)
    {
        Edge e=edges[p[x]];
        a=min(a,e.cap-e.flow);
        x=e.from;
    }
    x=t;
    while(x!=s)
    {
        edges[p[x]].flow+=a;
        edges[p[x]^1].flow-=a;
        x=edges[p[x]].from;
    }
    return a;
}
int maxflow(int s,int t)
{
    int flow=0,u=s;
    bfs(s,t);
    memset(gap,0,sizeof(gap));
    memset(cur,0,sizeof(cur));
    for(int i=0;i<=t;i++) gap[d[i]]++;
    while(d[s]<t+1)
    {
        if(u==t)
        {
            flow+=augment(s,t);
            u=s;
        }
        bool flag=false;
        for(int v=cur[u];v<G[u].size();v++) //Advance
        {
            Edge e=edges[G[u][v]];
            if(e.cap>e.flow&&d[u]==d[e.to]+1)
            {
                flag=true;
                p[e.to]=G[u][v];
                cur[u]=v;
                u=e.to;
                break;
            }
        }
        if(!flag) //Retreat
        {
            int m=t+1;
            for(int v=0;v<G[u].size();v++)
            {
                Edge e=edges[G[u][v]];
                if(e.cap>e.flow) m=min(m,d[e.to]);
            }
            if(--gap[d[u]]==0) break;
            gap[d[u]=m+1]++;
            cur[u]=0;
            if(u!=s) u=edges[p[u]].from;
        }
    }
    return flow;
}
int main()
{
    int T,n,k,id,num,no=0;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&num);
            for(int j=1;j<=num;j++)
            {
                scanf("%d",&id);
                paste[i][id]++;
            }
        }
        for(int i=1;i<=k;i++) //S->Bob
            if(paste[1][i]) {addedge(0,i,paste[1][i]);}
        for(int i=2;i<=n;i++) //Bob->friends
            for(int j=1;j<=k;j++)
            {
                if(paste[i][j]>=2) addedge(k+i,j,paste[i][j]-1);
                if(!paste[i][j]) addedge(j,k+i,1);
            }
        for(int i=1;i<=k;i++) addedge(i,k+n+1,1);//Bob->T
        printf("Case #%d: %d\n",++no,maxflow(0,k+n+1));
        for(int i=0;i<maxn;i++) G[i].clear();
        edges.clear();
        memset(paste,0,sizeof(paste));
    }
}
2817630 neopenx UVA 10779 Accepted 0 KB 16 ms C++ 4.8.2 3270 B 2014-10-05 13:48:15  
时间: 2024-08-09 02:18:14

UVA 10779 (最大流)的相关文章

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是

【网络流#4】UVA 753 最大流

最近开始刷网络流的题目了,先从紫书上的开始,这道题是P374上的,嘛,总之这道题最终还是参考了一下紫书. 中间是用了STL中map将字符串映射成编号,使用编号总比是用字符串简单的多. 超级源点S与各个设备对应插头类型连一条边,容量为1, 超级汇点T与各个插头连一条边,容量为1 然后如果有转换器,如果x->y,那么从点x连一条容量为正无穷的边到y (因为插头同类型的有无数个) 这样跑一发最大流即可,代码中间套用模板 1 #include<cstdio> 2 #include<cstr

【网络流#5】UVA 11082 最大流

网络流题目最有意思的地方就是构图了,毕竟套模板每个人都会的 现在有一个矩阵,已知前i行元素之和a[i](1<=i<=n),前j列元素之和b[j](1<=j<=m),求一个可行的矩阵,且矩阵每个元素在区间[1,20]内. 这也算是含上下界的网络流了,但是显然,如果将每个元素都减一,就是普通的最大流了,矩阵元素值在区间[0,19]内. 首先求出第i行元素之和r[i],第j列元素之和c[j], 然后就是建图,每行化为一个结点1~n,每列化为一个结点n+1~n+m 源点到1~n,分别连一条

UVa 11082 &amp; 最大流的行列模型

题意: 给出一个矩阵前i行的和与前j列的和,(i∈[1,r],j属于[1,c]),每个元素ai,j∈[1,20],请你还原出这个矩阵,保证有解. SOL: 给网络流建模跪了,神一样的建图,如果我我会怎么做呢?...搜索?然而每个元素具有行,列双重相关性...暴力都打不出来吧... 然而我们顺着搜索的方向想,如果每个点的搜索值最终小于这行的和,那么我们应该做什么?增大它!是不是感觉有点增广的想法出来了------>然而我只是瞎BB...事后觉得可以这么想但考场上并不能这么想出来... 考虑它的建图

Crimewave (Uva 563 最大流拆点)

 Crimewave  Nieuw Knollendam is a very modern town. This becomes clear already whenlooking at the layout of its map, which is just a rectangular grid of streetsand avenues. Being an important trade centre, Nieuw Knollendam also has a lotof banks. Alm

uva 10779 Collectors Problem

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

UVA 10779 Collectors Problem 网络流+建图

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

UVa 10806 &amp; 费用流+意识流...

题意: 一张无向图,求两条没有重复的从S到T的路径. SOL: 网络流为什么屌呢..因为网络流的容量,流量,费用能对许许多多的问题进行相应的转化,然后它就非常的屌. 对于这道题呢,不是要没有重复吗?不是一条边只能走一次吗?那么容量上界就是1.不是要有两条吗?那么总流量就是2.不是带权吗?那么加个费用. WA得惨不忍睹,最后发现边从0开始记异或以后会改变一些非常奇异的边...真是丝帛= = Code /*===============================================