很容易想到源点向所类型有贴纸连边,容量为Bob一开始有的数量;然后贴纸向汇点连边,容量为1。

接下来就是交换部分的连边了。注意交换一次一次进行,每次只能交换一张。

交换,是对于两种贴纸而言,仅会发生在一种贴纸朋友拥有的数量为0,而另一种朋友拥有的数量大于1。

于是这么建图,对于每一个朋友,如果贴纸数为0,那么这种贴纸向这个朋友连一条容量为1的边;如果数量x大于1,那边这个朋友向这种贴纸连一条容量为x-1的边。

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<queue>
  4. #include<algorithm>
  5. using namespace std;
  6. #define INF (1<<30)
  7. #define MAXN 55
  8. #define MAXM 55*55*2
  9.  
  10. struct Edge{
  11. int v,cap,flow,next;
  12. }edge[MAXM];
  13. int vs,vt,NE,NV;
  14. int head[MAXN];
  15.  
  16. void addEdge(int u,int v,int cap){
  17. edge[NE].v=v; edge[NE].cap=cap; edge[NE].flow=;
  18. edge[NE].next=head[u]; head[u]=NE++;
  19. edge[NE].v=u; edge[NE].cap=; edge[NE].flow=;
  20. edge[NE].next=head[v]; head[v]=NE++;
  21. }
  22.  
  23. int level[MAXN];
  24. int gap[MAXN];
  25. void bfs(){
  26. memset(level,-,sizeof(level));
  27. memset(gap,,sizeof(gap));
  28. level[vt]=;
  29. gap[level[vt]]++;
  30. queue<int> que;
  31. que.push(vt);
  32. while(!que.empty()){
  33. int u=que.front(); que.pop();
  34. for(int i=head[u]; i!=-; i=edge[i].next){
  35. int v=edge[i].v;
  36. if(level[v]!=-) continue;
  37. level[v]=level[u]+;
  38. gap[level[v]]++;
  39. que.push(v);
  40. }
  41. }
  42. }
  43.  
  44. int pre[MAXN];
  45. int cur[MAXN];
  46. int ISAP(){
  47. bfs();
  48. memset(pre,-,sizeof(pre));
  49. memcpy(cur,head,sizeof(head));
  50. int u=pre[vs]=vs,flow=,aug=INF;
  51. gap[]=NV;
  52. while(level[vs]<NV){
  53. bool flag=false;
  54. for(int &i=cur[u]; i!=-; i=edge[i].next){
  55. int v=edge[i].v;
  56. if(edge[i].cap!=edge[i].flow && level[u]==level[v]+){
  57. flag=true;
  58. pre[v]=u;
  59. u=v;
  60. //aug=(aug==-1?edge[i].cap:min(aug,edge[i].cap));
  61. aug=min(aug,edge[i].cap-edge[i].flow);
  62. if(v==vt){
  63. flow+=aug;
  64. for(u=pre[v]; v!=vs; v=u,u=pre[u]){
  65. edge[cur[u]].flow+=aug;
  66. edge[cur[u]^].flow-=aug;
  67. }
  68. //aug=-1;
  69. aug=INF;
  70. }
  71. break;
  72. }
  73. }
  74. if(flag) continue;
  75. int minlevel=NV;
  76. for(int i=head[u]; i!=-; i=edge[i].next){
  77. int v=edge[i].v;
  78. if(edge[i].cap!=edge[i].flow && level[v]<minlevel){
  79. minlevel=level[v];
  80. cur[u]=i;
  81. }
  82. }
  83. if(--gap[level[u]]==) break;
  84. level[u]=minlevel+;
  85. gap[level[u]]++;
  86. u=pre[u];
  87. }
  88. return flow;
  89. }
  90.  
  91. int main(){
  92. int t,n,m,a,b;
  93. scanf("%d",&t);
  94. for(int cse=;cse<=t;++cse){
  95. scanf("%d%d",&n,&m);
  96. memset(head,-,sizeof(head));
  97. vs=; vt=n+m+; NV=vt+; NE=;
  98.  
  99. scanf("%d",&a);
  100. int cnt[]={};
  101. while(a--){
  102. scanf("%d",&b);
  103. ++cnt[b];
  104. }
  105. for(int i=;i<=m;++i){
  106. if(cnt[i]==) continue;
  107. addEdge(vs,i,cnt[i]);
  108. }
  109.  
  110. for(int i=;i<=m;++i) addEdge(i,vt,);
  111.  
  112. for(int i=;i<=n;++i){
  113. scanf("%d",&a);
  114. int cnt[]={};
  115. while(a--){
  116. scanf("%d",&b);
  117. ++cnt[b];
  118. }
  119. for(int j=;j<=m;++j){
  120. if(cnt[j]>=){
  121. addEdge(i+m,j,cnt[j]-);
  122. }else if(cnt[j]==){
  123. addEdge(j,i+m,);
  124. }
  125. }
  126. }
  127.  
  128. printf("Case #%d: %d\n",cse,ISAP());
  129. }
  130. return ;
  131. }

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

  1. UVA10779 Collectors Problem

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

  2. UVA-10779 Collectors Problem

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

  3. UVA 10779 Collectors Problem(最大流)

    这个题是很难往网络流上面构思的... 从s向每个物品增加容量为Bob拥有数的弧,然后从每个物品向t增加容量为1的弧(代表种类个数).这时候跑最大流的话,得到的肯定是Bob拥有的初始种类数.那么交换后的 ...

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

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

  5. UVA10779 Collectors Problem 【迁移自洛谷博客】

    这是一道不错的练最大流建模的基础题. 这种题目审题是关键. Bob's friends will only exchange stickers with Bob, and they will give ...

  6. Flow Problem(最大流模板)

    Flow Problem Time Limit: 5000/5000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Tota ...

  7. [Bob]Collectors Problem

    https://vjudge.net/problem/UVA-10779#author=0 网络流 1.Bob向他有的贴纸连边,流量为他有的贴纸数量 2.每一种贴纸向汇点连流量为1的边 3.其余人,如 ...

  8. hdu 3549 Flow Problem (最大流)

    裸最大流,做模板用 m条边,n个点,求最大流 #include <iostream> #include <cstdio> #include <cstring> #i ...

  9. uva 10779 Collectors Problem 网络流

    链接 一共有n个人, m种收藏品, 每个人拥有的收藏品的种类和个数都是不相同的. 假设2-n这些人都只和1互相交换, 比例是1:1, 并且, 2-n这些人, 只换自己现在没有的, 如果他现在有第二种, ...

随机推荐

  1. poj3026(bfs+prim)

    The Borg is an immensely powerful race of enhanced humanoids from the delta quadrant of the galaxy. ...

  2. linux下查看文件夹的大小

    du -sh du -sh dir_name/ du -sm * | sort -n //统计当前目录大小 并安大小排序 转自:http://www.jb51.net/LINUXjishu/77450 ...

  3. 【OpenStack】OpenStack系列16之OpenStack镜像制作

    参考 参考: https://www.google.com.hk/?gws_rd=ssl#safe=strict&q=openstack+img+%E5%88%B6%E4%BD%9C http ...

  4. IIS安装时,添加/编辑应用程序扩展名映射 确定按钮不可用。

    原因是:执行文件的路径太长,需要激活按钮. 方法一:选择较短路径的执行文件,先激活按钮. 方法二:点击该路径,就可以激活确认按钮了.

  5. HTML模仿桌面

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  6. Android 启动画面

    如果你的程序初始化时间过长,那么在初始化之前,程序会现实一个空白的activity页,十分难看. 添加一个启动画面的方法就是为响应的activity加入自定义的Theme,并在theme中设定 and ...

  7. 虚析构函数(√)、纯虚析构函数(√)、虚构造函数(X)

    from:http://blog.csdn.net/fisher_jiang/article/details/2477577 一. 虚析构函数 我们知道,为了能够正确的调用对象的析构函数,一般要求具有 ...

  8. xtrabackup 增量备份(InnoDB)

    mysql> select * from users; +----+-----------+----------+--------------+ | id | name | password | ...

  9. undefined reference to libiconv_open'

    ext/iconv/.libs/iconv.o: In function `php_iconv_stream_filter_ctor': /home/king/php-5.2.13/ext/iconv ...

  10. NVelocity模板引擎的使用

    第一种使用方法直接赋值: VelocityEngine vltEngine = new VelocityEngine(); vltEngine.SetProperty(RuntimeConstants ...