这是一道不错的练最大流建模的基础题。
这种题目审题是关键。
Bob’s friends will only exchange stickers with Bob, and they will give away only
duplicate stickers in exchange with different stickers they don’t possess.
意思就是说,Bob的朋友们只会和Bob交换贴纸,并且呢,他们只会赠送给Bob他们有的重复的的贴纸,以换取他们没有的贴纸。
上面还有一段话,But Bob is clever: he has realized that in some cases it is good for him to trade one of his duplicate stickers for a sticker he already possesses.就是说,Bob他可能会有自己重复的贴纸去换他已经有的贴纸。(这样就可以再用这一张贴纸去换其他他没有的贴纸了)

题目问的是Bob最多可以得到多少贴纸。

很明显,根据以往的经验,这是一个网络流的模型。我们应该把所有的人,所有的贴纸都用一个点来表示一下。任何贴纸之间应该怎么建边呢? 首先,把一个人(Bob除外),向他可以交换给别人的贴纸(数量>=2)上建边,容量应该为他所拥有此类贴纸数量-1。

然后也可以把一个贴纸向所有不具有它的人连一条边,容量为1(因为每种贴纸一个人只会要一次),表示把这个贴纸交换过来了。这样一来,我们每流过一个点,一定是进来一次,出来一次,可以很好地表示一次交换。

但是这个成立前提是什么呢?这些贴纸肯定是从Bob开始交换的,也是最后流回Bob的手里的。那么,Bob本人也应该向她所拥有的贴纸建边,边权为他拥有的这类贴纸的数量。为什么不用减1呢?这个问题我们留到后面来解决。

我们还需要再建一个点T,让所有的贴纸都指向T,边权为1。因为每一类贴纸只算一次。我们就可以用从Bob到这个点T的最大流表示Bob可以收集到的贴纸最多有多少类了。其实T这个点,也是用来表示Bob这个人的另一个点。

现在让我们汇过来看刚刚那一个问题。因为Bob的贴纸种类,最终是通过刚刚我们建的那个点T来统计的,所以我们必须把这个留下的贴纸也流过去。就算这个贴纸被换成了其他贴纸了,那也不会影响结果——因为我们建立的这个网络,不会让一类贴纸流到两次到T的,因此即使那个贴纸被换成了其他贴纸,这个贴纸还是唯一的,不会影响总的种类数。

为了便于大家理解,我来画个图。

上面三个图,是样例二的模型。其中S是Bob,BC是其他两个人。1234是四种贴纸(题目说有5中,但第五种没有出现)。为了便于分清边的方向,从两边到中间的边是黑色的,从中间到两边的是蓝色的。
每个图加粗的边都是一个单位的流,流一和流三这样从S流到T可以很好地表示Bob本来就有这样的一个贴纸。流二则可以很形象地表示Bob把一张贴纸1和B换来一个贴纸2,有把这个贴纸2从C出换来贴纸3。

这样的话,每一个单位的流,就表示一种贴纸的来龙去脉,如此,最大流是几,就可以表示Bob最多可以收集到多少种贴纸。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std; const int maxn=10+7,maxm=25+7,INF=0x7f7f7f7f;
int Test,Cas,n,m,x,y,S,T;
int cnt[maxm]; int head[maxn+maxm],tot=-1;
struct Edge{int u,v,flow,ne;}g[maxm*maxn<<4];
inline void addedge(int x,int y,int z){
g[++tot].u=x;g[tot].v=y;g[tot].flow=z;g[tot].ne=head[x];head[x]=tot;
g[++tot].u=y;g[tot].v=x;g[tot].flow=0;g[tot].ne=head[y];head[y]=tot;
} int cur[maxn+maxm],dist[maxn+maxm];queue<int>q;
bool bfs(int s,int t){
memset(dist,0x7f,sizeof(dist));dist[s]=0;q.push(s);for(register int i=S;i<=T;++i)cur[i]=head[i];
while(!q.empty()){int x=q.front();q.pop();for(register int i=head[x];~i;i=g[i].ne)if(g[i].flow&&dist[g[i].v]==INF)dist[g[i].v]=dist[x]+1,q.push(g[i].v);}
return dist[t]<INF;
}
int dfs(int x,int t,int a){
if(x==t||!a)return a;int flow=0,f;
for(register int &i=cur[x];~i;i=g[i].ne)if(dist[g[i].v]==dist[x]+1&&(f=dfs(g[i].v,t,min(a,g[i].flow)))){g[i].flow-=f;g[i^1].flow+=f;flow+=f;a-=f;if(!a)break;}
return flow;
}
inline int Dinic(int s,int t){int ans=0;while(bfs(s,t))ans+=dfs(s,t,INF);return ans;}
//上面是Dinic部分,不用说了吧
void Clear(){tot=-1;memset(head,-1,sizeof(head));} void Init(){
Clear();scanf("%d%d",&n,&m);S=1,T=n+m+1;
for(register int i=1;i<=n;++i){
scanf("%d",&x);memset(cnt,0,sizeof(cnt));for(register int j=1;j<=x;++j){scanf("%d",&y);++cnt[y];}//cnt用来统计这个人有每种贴纸多少张
if(i==1)for(register int j=1;j<=m;++j){if(cnt[j])addedge(S,j+n,cnt[j]);}//1就是Bob,这里把Bob向他有的贴纸建边
else for(register int j=1;j<=m;++j)if(cnt[j]>1)addedge(i,j+n,cnt[j]-1);else if(!cnt[j])addedge(j+n,i,1);//如果这个人有这种贴纸多于1张,就可以用来和别人交换其他贴纸,因此和这种贴纸建边。否则,若此人没有这种贴纸,就可以从别人那里获得,就让那种贴纸向他建边
}
for(register int i=1;i<=m;++i)addedge(i+n,T,1);//每种贴纸向终点建边
} void Work(){
printf("Case #%d: %d\n",++Cas,Dinic(S,T));
} int main(){
scanf("%d",&Test);
while(Test--){
Init();
Work();
}
}

——发表于2018-04-24 15:01:53

UVA10779 Collectors Problem 【迁移自洛谷博客】的更多相关文章

  1. Uva10491 Cows and Cars 【迁移自洛谷博客】

    题目大意 假设有a头牛,b辆车(门的总数为a+b),你先选一个门,然后你最终选择前主持人会替你打开C扇有牛的门(不会打开你已经选择的门),问你要不要换门,输出"总是换门"的策略下, ...

  2. UVa1636 Headshot 【迁移自洛谷博客】

    说明:小蒟蒻hkk现在正在做一些概率的题目,由于这方面和数学还有点关系,所以需要一些数学的思维,也需要表述出来,如夏军所述"把自己给讲懂",所以写了些blog,主要为帮助自己理解. ...

  3. JSOI2018冬令营游记&总结(迁移自洛谷博客)

    游记 一开始在冬令营还没开始的时候,十分期待,殊不知每天都有一场浩劫在等着我. Day0 10:50出发,看见lbn同学发了一条说说,也随便发了一个. 然后在车上一直在睡觉,现在感觉挺后悔的,其实可以 ...

  4. UVA-10779 Collectors Problem

    https://vjudge.net/problem/UVA-10779 题意:n个人,m种贴纸,每个人开始有一些贴纸 第一个人可以跟任何人交换任何贴纸 其余人只能用重复的贴纸 跟第一个人交换他们没有 ...

  5. UVA10779 Collectors Problem

    题目链接:https://cn.vjudge.net/problem/UVA-10779 前言: 本题是关于姜志豪<网络流的一些建模方法>的笔记. 知识点: 最大流 题意摘抄: \(Bob ...

  6. UVa10779 Collectors Problem(最大流)

    很容易想到源点向所类型有贴纸连边,容量为Bob一开始有的数量:然后贴纸向汇点连边,容量为1. 接下来就是交换部分的连边了.注意交换一次一次进行,每次只能交换一张. 交换,是对于两种贴纸而言,仅会发生在 ...

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

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

  8. 洛谷3388 tarjan割点

    题目链接:https://www.luogu.com.cn/problem/P3388 tarjan算法果然牛逼,时间复杂度是O(|V|+|E|),所以1e4个结点2e5条边的图完全不在话下orz o ...

  9. 他是 ISIJ 第四名,也是在线知名题库的洛谷“网红”

    转载自加藤惠. 2020年国际初中生信息学竞赛(ISIJ)上,以优秀成绩拿下第四名年仅初三的张湫阳,成为最夺目的选手之一. 而且虽然是初三的选手,但他取得优异成绩后,不少网友并不感到陌生,纷纷留言: ...

随机推荐

  1. python网络编程之验证客户端链接的合法性

    六.socket的更多方法介绍 服务端套接字函数s.bind() 绑定(主机,端口号)到套接字s.listen() 开始TCP监听s.accept() b被动接收TCP客户的连接,(阻塞式)等待连接的 ...

  2. Delphi实现获取磁盘空间大小的方法

    unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ...

  3. [CSP-S模拟测试]:飞(fly)(数状数组+简单几何)

    题目描述 $liu\_runda$决定提高一下知识水平,于是他去请教郭神.郭神随手就给了$liu\_runda$一道神题,$liu\_runda$并不会做,于是把这个题扔到联考里给高二的做.郭神有$n ...

  4. Step3 - How to: Host and Run a Basic Windows Communication Foundation Service

    This is the third of six tasks required to create a Windows Communication Foundation (WCF) applicati ...

  5. ceph-性能调优

    Ceph 参数性能调优https://blog.csdn.net/changtao381/article/details/49907115这篇文章对我的环境有较大帮助 ceph优化记录 ceph.co ...

  6. CSS-同一行的元素高度统一

    一:flex 大法 步骤 设置外部容器 display: flex; 设置内部容器 align-items: stretch; 原理 https://developer.mozilla.org/zh- ...

  7. 测开之路七十七:性能测试蓝图之js

    //定义全局的editor = nullvar editor = null; //ace_editor的初始化函数function ace_editor() { var editor = ace.ed ...

  8. 机器学习实战笔记-2-kNN近邻算法

    # k-近邻算法(kNN) 本质是(提取样本集中特征最相似数据(最近邻)的k个分类标签). K-近邻算法的优缺点 例 优点:精度高,对异常值不敏感,无数据输入假定: 缺点:计算复杂度高,空间复杂度高: ...

  9. Visual Studio中把文件夹导入工程中

    VS用到的功能还是太少,记录备忘. 有的时候需要把其他库的源码导入当前工程直接使用,而这个库是源码形式,又带很多目录的. 之前从没遇到过这种情况,自己的库目录自己新建,添加. 第三方库一般有单独的Pr ...

  10. python datetime模块的strftime()

    strftime()   可以对datetime对象进行格式化,生成需要时间格式的时间 strptime()  可以对格式化后的时间再生成datetime对象 格式化时间时,如果不想要-来隔开,还可以 ...