题目描述

«问题描述:

给定有向图G=(V,E)。设P 是G 的一个简单路(顶点不相交)的集合。如果V 中每个顶点恰好在P 的一条路上,则称P是G 的一个路径覆盖。P 中路径可以从V 的任何一个顶点开始,长度也是任意的,特别地,可以为0。G 的最小路径覆盖是G 的所含路径条数最少的路径覆盖。设计一个有效算法求一个有向无环图G 的最小路径覆盖。提示:设V={1,2,.... ,n},构造网络G1=(V1,E1)如下:

每条边的容量均为1。求网络G1的( 0 x , 0 y )最大流。

«编程任务:

对于给定的给定有向无环图G,编程找出G的一个最小路径覆盖。

输入输出格式

输入格式:

件第1 行有2个正整数n和m。n是给定有向无环图G 的顶点数,m是G 的边数。接下来的m行,每行有2 个正整数i和j,表示一条有向边(i,j)。

输出格式:

从第1 行开始,每行输出一条路径。文件的最后一行是最少路径数。

输入输出样例

输入样例#1:

  1. 11 12
  2. 1 2
  3. 1 3
  4. 1 4
  5. 2 5
  6. 3 6
  7. 4 7
  8. 5 8
  9. 6 9
  10. 7 10
  11. 8 11
  12. 9 11
  13. 10 11
输出样例#1:

  1. 1 4 7 10 11
  2. 2 5 8
  3. 3 6 9
  4. 3

说明

1<=n<=150,1<=m<=6000

思路:

  网络流24题之一;

  还是那条性质,求最小割;

  每条有向边的u,v加边都是u,v+n;

  求出最大流,ans=n-最大流;

  然后,我们在求最大流的时候把匹配的点和边做标记以输出路径;

来,上代码:

  1. #include <queue>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <iostream>
  5. #include <algorithm>
  6.  
  7. #define INF 0x7ffffff
  8.  
  9. using namespace std;
  10.  
  11. struct EdgeType {
  12. int to,next,flow;
  13. };
  14. struct EdgeType edge[];
  15.  
  16. int if_z,n,m,cnt=,head[],s=,t=;
  17. int deep[],next[],ans;
  18.  
  19. bool if_[];
  20.  
  21. char Cget;
  22.  
  23. inline void in(int &now)
  24. {
  25. now=,if_z=,Cget=getchar();
  26. while(Cget>''||Cget<'')
  27. {
  28. if(Cget=='-') if_z=-;
  29. Cget=getchar();
  30. }
  31. while(Cget>=''&&Cget<='')
  32. {
  33. now=now*+Cget-'';
  34. Cget=getchar();
  35. }
  36. now*=if_z;
  37. }
  38.  
  39. inline void edge_add(int u,int v,int w)
  40. {
  41. edge[++cnt].to=v,edge[cnt].flow=w,edge[cnt].next=head[u],head[u]=cnt;
  42. edge[++cnt].to=u,edge[cnt].flow=,edge[cnt].next=head[v],head[v]=cnt;
  43. }
  44.  
  45. bool BFS()
  46. {
  47. queue<int>que;
  48. memset(deep,-,sizeof(deep));
  49. que.push(s),deep[s]=;
  50. while(!que.empty())
  51. {
  52. int pos=que.front();
  53. for(int i=head[pos];i;i=edge[i].next)
  54. {
  55. if(deep[edge[i].to]<&&edge[i].flow>)
  56. {
  57. deep[edge[i].to]=deep[pos]+;
  58. if(edge[i].to==t) return true;
  59. que.push(edge[i].to);
  60. }
  61. }
  62. que.pop();
  63. }
  64. return false;
  65. }
  66.  
  67. int flowing(int now,int flow)
  68. {
  69. if(now==t||flow==) return flow;
  70. int oldflow=;
  71. for(int i=head[now];i;i=edge[i].next)
  72. {
  73. if(deep[edge[i].to]!=deep[now]+||edge[i].flow==) continue;
  74. int pos=flowing(edge[i].to,min(flow,edge[i].flow));
  75. if(pos>)
  76. {
  77. next[now]=edge[i].to;
  78. if(edge[i].to>n) if_[edge[i].to-n]=true;
  79. }
  80. flow-=pos;
  81. oldflow+=pos;
  82. edge[i].flow-=pos;
  83. edge[i^].flow+=pos;
  84. if(flow==) return oldflow;
  85. }
  86. return oldflow;
  87. }
  88.  
  89. void dinic()
  90. {
  91. while(BFS()) ans-=flowing(s,INF);
  92. }
  93.  
  94. int main()
  95. {
  96. in(n),in(m);int u,v;ans=n;
  97. for(int i=;i<=m;i++)
  98. {
  99. in(u),in(v);
  100. edge_add(u,v+n,INF);
  101. }
  102. for(int i=;i<=n;i++)
  103. {
  104. edge_add(s,i,);
  105. edge_add(i+n,t,);
  106. }
  107. dinic();
  108. for(int i=;i<=n;i++)
  109. {
  110. if(if_[i]) continue;
  111. int pos=i;
  112. printf("%d",pos);
  113. while(next[pos])
  114. {
  115. if(next[pos]>n) next[pos]-=n;
  116. printf(" %d",next[pos]);
  117. pos=next[pos];
  118. }
  119. printf("\n");
  120. }
  121. printf("%d\n",ans);
  122. return ;
  123. }

AC日记——最小路径覆盖问题 洛谷 P2764的更多相关文章

  1. AC日记——无线网络发射器选址 洛谷 P2038

    题目描述 随着智能手机的日益普及,人们对无线网的需求日益增大.某城市决定对城市内的公共场所覆盖无线网. 假设该城市的布局为由严格平行的129 条东西向街道和129 条南北向街道所形成的网格状,并且相邻 ...

  2. AC日记——校门外的树 洛谷 P1047

    题目描述 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0,1,2,……,L,都种 ...

  3. AC日记——小A的糖果 洛谷七月月赛

    小A的糖果 思路: for循环贪心: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 100005 #defi ...

  4. AC日记——矩阵取数游戏 洛谷 P1005

    矩阵取数游戏 思路: dp+高精: 代码: #include <bits/stdc++.h> using namespace std; #define ll long long struc ...

  5. AC日记——红色的幻想乡 洛谷 P3801

    红色的幻想乡 思路: 线段树+容斥原理: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 100005 #de ...

  6. AC日记——妖梦拼木棒 洛谷 P3799

    妖梦拼木棒 思路: 神特么题: 代码: #include <bits/stdc++.h> using namespace std; #define mod 1000000007LL int ...

  7. AC日记——妖梦斩木棒 洛谷 P3797

    妖梦斩木棒 思路: 略坑爹: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 200005 #define m ...

  8. AC日记——[SDOI2009]HH去散步 洛谷 P2151

    [SDOI2009]HH去散步 思路: 矩阵快速幂递推(类似弗洛伊德): 给大佬跪烂-- 代码: #include <bits/stdc++.h> using namespace std; ...

  9. AC日记——聪明的质监员 洛谷 P1314

    聪明的质监员 思路: 二分: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 200005 #define l ...

随机推荐

  1. destoon后台权限-不给客户创始人权限并屏蔽部分功能

    1.根目录下后台入口文件admin.php $_founder = $CFG['founderid'] == $_userid ? $_userid : 0;  //  $CFG['founderid ...

  2. jsp内置对象及其方法

    JSP中一共预先定义了9个这样的对象,分别为:   request.   response.   session.   application.   out.   pagecontext.   con ...

  3. linux中vim永久显示行号、开启语法高亮

    vim ~/.vimrc 进入insert模式,在最后加二行 syntax on set nu! 保存收工. 设置用视图模式的缩进为4个空格 set smartindent set tabstop=4 ...

  4. STM32CUBEMX入门学习笔记1:软件的简单介绍

    STM32CUBEMX是ST公司设计的一款免费软件,软件可以通过其官网下载.现在已经下载到.通过STM32CUBEMX可以完成从单片机选型,程序初始化,中断配置……工作.并生成对应的"HAL ...

  5. STVP烧录教程

    可以运行独立的烧录软件ST Visual Programmer (STVP)进行STM8芯片烧录.运行“开始”->ST Toolset->Development Tools -> S ...

  6. Freemaker模板指令

    ${...}:Freemaker将会输出真实的值来替换大括号内的表达式.这样的表达式被称为interpolation(插值). FTL标签(Freemaker模板的语言标签):FTL标签和HTML标签 ...

  7. 蓝桥杯Java输入输出相关

    转载自:http://blog.csdn.net/Chen_Tongsheng/article/details/53354169 一.注意点 1. 类名称必须采用public class Main方式 ...

  8. C++ 指针的小知识

    看个小例子: char* fun1(){ char * p = (char*)malloc(100); p = "helloww"; return p;} void fun2(ch ...

  9. 在线安装ipa,超链接下载ipa

    在线安装ipa包其实是OTA实现,先粘一下OTA解释 OTA OTA即Over-the-Air,简单来说就是通过无线的方式发送指令给设备,具体针对iOS的设备,比如iphone .ipad等,让开发者 ...

  10. LiveScript 流程控制、循环以及列表推导式

    The LiveScript Book     The LiveScript Book Generators and Yield 你可以在你的 LiveScript 代码中使用 Ecmascript ...