网络流与线性规划24题03最小路径覆盖问题
来源:互联网 发布:如何运营淘宝商城 编辑:程序博客网 时间:2024/06/05 20:29
问题描述:
给定有向图G=(V,E)。设P 是G 的一个简单路(顶点不相交)的集合。如果V 中每个
顶点恰好在P 的一条路上,则称P是G 的一个路径覆盖。P 中路径可以从V 的任何一个顶
点开始,长度也是任意的,特别地,可以为0。G 的最小路径覆盖是G 的所含路径条数最少
的路径覆盖。
设计一个有效算法求一个有向无环图G 的最小路径覆盖。
编程任务:
对于给定的给定有向无环图G,编程找出G的一个最小路径覆盖。
数据输入:
文件input.txt提供输入数据。文件第1 行有2个正整数n和m。n是给定有向无环图
G 的顶点数,m是G 的边数。接下来的m行,每行有2 个正整数i和j,表示一条有向边(i,j)。
结果输出:
程序运行结束时,将最小路径覆盖输出到文件output.txt 中。从第1 行开始,每行输出
一条路径。文件的最后一行是最少路径数。
输入示例:
11 12
1 2
1 3
1 4
2 5
3 6
4 7
5 8
6 9
7 10
8 11
9 11
10 11
输出示例:
1 4 7 10 11
2 5 8
3 6 9
3
分析:
最小路径覆盖,还是一窍不通,百度百科了一下最小路径覆盖。
对于一个路径覆盖,有如下性质:
1、每个顶点属于且只属于一个路径。
2、路径上除终点外,从每个顶点出发只有一条边指向路径上的另一顶点。
我们可以把每个顶点理解成两个顶点,一个是出发,一个是目标,建立二分图模型。该二分图的任何一个匹配方案,都对应了一个路径覆盖方案。如果匹配数为0,那么显然路径数=顶点数。每增加一条匹配边,那么路径覆盖数就减少一个,所以路径数=顶点数 - 匹配数。要想使路径数最少,则应最大化匹配数,所以要求二分图的最大匹配。
所以最小路径覆盖数=顶点数-最大匹配数。最后输出结果只要沿着匹配边查找即可。
于是这题就转化成了二分图最大匹配问题,二分图又可以用最大流求解。于是目的达到了。
然后今天新学习了一个最短增广路的算法,dinic算法,就是增广层次图和阻塞流来找增广路。用BFS生成增广层次图,用DFS查找阻塞流。
该算法在二分图最大匹配下时间效率可达O(m*n^1/2),而之前的BFS直接查找增广路高达O(n*m^2);这个算法不是最快的,该算法的优点是概念简洁,速度较快。
图的数据结构是邻接表,采用了刘汝佳白书上推荐的STL的vector来表示邻接表,虽然时间效率不是最高的,但是代码很清晰,且容易写,也容易调试。
由于本人比较懒,所以成员函数就写在声明里面了。
最后吐槽一点,还是对二分图理解不深刻,用最大流求解加源点汇点的时候,理解错了,把汇点汇点相应连接的点权值设成无穷,而不是1,导致调试了N个小时,太桑感了。
dinic求二分图最大匹配:
#include<cstdio>#include<vector>#include<iostream>#include<queue>#include<cstring>using namespace std;const int MAX = 1000;const int INF = 10000000;struct Edge{//边结构体 int from,to,cap,flow;Edge(int a,int b,int c,int d):from(a),to(b),cap(c),flow(d){}};struct dinic{ int n,m,s,t; vector<int> g[MAX];//邻接表 vector<Edge> edges;//边集 int d[MAX]; int cur[MAX]; bool visit[MAX]; dinic(int nn,int mm) { s=0;t=2*nn+1;//源点0,汇点2*n+1 edges.clear(); for(int i=0;i<=nn+1;i++) g[i].clear(); n=nn;m=mm; int x,y; //除了源点汇点,把每个点i,分成i和i+n,i是出发点,i+n是目标点 for(int i=0;i<m;i++){ scanf("%d%d",&x,&y); add(x,y+n,1); } for(int i=1;i<=n;i++){ add(s,i,1);//源点到1~n add(i+n,t,1);//n+1~2*n } } void add(int from,int to,int cap) { edges.push_back(Edge(from,to,cap,0)); edges.push_back(Edge(to,from,0,0)); int l=edges.size(); g[from].push_back(l-2); g[to].push_back(l-1); } bool BFS()//bfs增广层次图 { memset(visit,false,sizeof(visit)); queue<int> q; q.push(s); d[s]=0; visit[s]=true; while(!q.empty()){ int x=q.front();q.pop(); for(int i=0;i<g[x].size();i++){ Edge &e=edges[g[x][i]]; if(!visit[e.to]&&e.cap>e.flow){ visit[e.to]=true; d[e.to]=d[x]+1; q.push(e.to); } } } return visit[t]; } int DFS(int x,int a){//dfs求最大流 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[x]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0){ e.flow+=f; edges[g[x][i]^1].flow-=f; flow+=f; a-=f; if(a==0) break; } } return flow; } int maxflow()//返回最大流 { int flow=0; while(BFS()){ memset(cur,0,sizeof(cur)); flow+=DFS(s,INF); }return flow; } void show(int i)//输出路径 { visit[i]=true; for(int j=0;j<g[i].size();j++){ Edge &e=edges[g[i][j]]; if(!visit[e.to]&&e.to!=t&&1==e.flow){ printf(" %d",e.to-n); show(e.to-n); } } } void print()//输出路径 {int x=maxflow();memset(visit,false,sizeof(visit)); for(int i=1;i<=n;i++){ if(!visit[i]){ printf("%d",i); show(i); printf("\n"); } } printf("%d\n",n-x); }};int main(){ int n,m; scanf("%d%d",&n,&m); dinic d(n,m); d.print(); return 0;}
- 线性规划与网络流24题の3 最小路径覆盖问题(最小路径覆盖)
- 线性规划与网络流 03最小路径覆盖问题
- 线性规划与网络流24题 03最小路径覆盖问题
- 线性规划与网络流24题——03最小路径覆盖问题
- 网络流与线性规划24题03最小路径覆盖问题
- 【线性规划与网络流24题 3】最小路径覆盖
- 线性规划与网络流24题 3最小路径覆盖问题 NEFU 481
- 线性规划与网络流24题之最小路径覆盖问题
- 线性规划与网络流24题の4 魔术球问题(最小路径覆盖)
- 线性规划与网络流24题 3.最小路径覆盖问题(nefu 481)
- 线性规划与网络流24——最小路径覆盖问题
- [网络流24题] 03 最小路径覆盖问题(有向无环图最小路径覆盖,网络最大流)
- 网络流24题3最小路径覆盖问题(洛谷 P2764 最小路径覆盖问题)
- [网络流24题 #3]最小路径覆盖问题
- [网络流24题] 最小路径覆盖问题
- kyeremal-网络流24题T3-最小路径覆盖问题
- 【二分匹配】 [网络流24题] 最小路径覆盖问题
- code vs [网络流24题]最小路径覆盖问题
- HSI、HSV、RGB、CMY、CMYK、HSL、HSB、Ycc、XYZ、Lab、YUV颜色模型
- 线程同步
- ZOJ 1181 Word Amalgamation
- Logback基础
- 树莓派 关闭swap 文件
- 网络流与线性规划24题03最小路径覆盖问题
- redhat5下mysql5.5.28的安装与卸载
- 数据结构(C#)--递归和动态规划法实现斐波那契数列的方法
- Code Complete 变量名的力量
- jQuery(3)--实现注册表单中当用户名为空时,实现输入框边框变色
- 3-19java的日子
- 在什么时间更新站内文章最好呢
- jQuery设计思路与编程理念,j优雅js库的内部秘密
- 三个wiki平台的试用总结