C++之求有向无环图的最长路径(拓扑排序+动态规划)
来源:互联网 发布:淘宝女装店铺头像 编辑:程序博客网 时间:2024/05/17 03:00
最近在做求有向无环图的最长路径的问题,当然,求最长路径有许多方法,比如可以直接用Floyd算法来求,只需稍微改动一下,不过用拓扑排序+动态规划来做,百度搜索了一下,介绍这方面的资料不够完善,也许会让许多人不够清楚实现原理,在这里,我讲解一下自己的一些思路,分成四部分进行编程:
一、创建有向无环图:
我用的数据存储结构是邻接矩阵,如果用邻接表也是可以的。这里就不多作解释,直接进入关键代码部分。
二、拓扑排序:
官方解释是:对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。
用通俗的话来讲就是,比如你要选课A、B、C,但是读B要先选A,读A要先选C,所以,进行拓扑排序后,就是C、A、B。
所以在创建图的时候,要用一个标志数组indegree[]来保存每个顶点的入度,另外,在进行下面求最长路径的时候,需要用到拓扑排序的结果,所以还需要一个数组topo[]来记录拓扑排序的结果。
拓扑排序里,都先找到入度为0的顶点,然后把它取出来(让它的入度等于负数进行实现),保存在topo[]里面,接着更新其他与这个顶点相邻的其他顶点的入度,最后,循环即可。
三、求最长路径:
只要知道了动态规划的公式就好,这里直接给出公式maxPath[v]=max{maxPaht[v],maxPath[k]+e[k][v]},其中maxPath[v]表示的是起始点到点v的最长路径,e[k][v]表示点k到点v的距离。这个公式的意思是,假如有A、B、C三个点,求maxPath[C],要么直接取maxPath[C],要么取maxPath[A]+e[A][C],要么取maxPath[B]+e[B][C]。当然,这个公式的所需要的顶点需要按顺序取自拓扑排序的结果,否则,有可能在进行求maxPath[k]+e[k][v]的时候,maxPath[k]并不是最长的,造成结果出错。
四、求最长路线:
这个我想了挺久的,最后想到的方法是用一个二维矩阵(N*N)保存每一个点到点的最长路径,对第N列进行排序,取出第N列中最大的一个数a,记录下行号R和列号C(在v1—>v2中,行对应的是v1,列对应的是v2),然后把列号C压进栈里(输出的时候直接输出就是最长路线了),接着按照这个数字a的行号R找到相同数字的列号R'(比如a数字在的位置是[4][5],行号是4,则找到第4列),令N=R‘,重复以上步骤即可。
下面贴出源代码仅供参考:
#include <iostream>#include <algorithm>#include <stack>using namespace std;char *v;//顶点数组,下标为顶点号,值为顶点名称(用在创建有向无环图中)int **e;//边的二维矩阵(用在创建有向无环图中)int *indegree;//保存顶点入度数的数组(求拓扑排序)int *topo;//保存拓扑排序结果的数组(求拓扑排序)int *maxPath;//保存到此点的最长路径(求最长路径)//创建有向无环图void creatGraph(int vSize,int eSize){//初始化int i,j,k,c;char a,b;indegree=new int[vSize];topo=new int[vSize]; v=new char[vSize];e=new int*[vSize];for(i=0;i<vSize;i++) e[i]=new int[vSize];for(i=0;i<vSize;i++)for(j=0;j<vSize;j++)e[i][j]=0;for(i=0;i<vSize;i++){indegree[i]=0;topo[i]=0;}//建图cout<<endl<<"请输入各顶点名称:";for(i=0;i<vSize;i++)cin>>v[i];cout<<endl<<"请先后输入顶点V1和V2(表示V1->V2)以及权值,按换行键继续"<<endl;for(i=0;i<eSize;i++){ cin>>a>>b>>c;for(j=0;j<vSize;j++) if(v[j]==a) break;for(k=0;k<vSize;k++) if(v[k]==b) break; e[j][k]=c; indegree[k]++;//入度+1}}//拓扑排序void topologicalSort(int vSize){int i,j,k;for(i=0;i<vSize;i++) //vSize次循环{j=0;while(j<vSize&&indegree[j]!=0) j++;//找到入度为0的顶点topo[i]=j;//保存indegree[j]=-1;// 设结点j为入度为-1,以免再次输出jfor(k=0;k<vSize;k++)//更新其他入度点if(e[j][k]!=0)indegree[k]--;}}//最长路径void getMaxPath(int vSize){//初始化int i,j,k,v1,v2,max=0,**path,*p;maxPath=new int[vSize]; //保存最长路径,表示到顶点N的最长路径p=new int[vSize]; //用来处理最长路线的选择顶点 path=new int*[vSize]; //用来保存点到点的最长路径矩阵for(i=0;i<vSize;i++) path[i]=new int[vSize];for(i=0;i<vSize;i++)for(j=0;j<vSize;j++)path[i][j]=0;for(i=0;i<vSize;i++){ maxPath[i]=0;p[i]=0;}//关键代码,求最长路径for(j=0;j<vSize;j++){v2=topo[j];for(k=0;k<j;k++){ v1=topo[k]; if(e[v1][v2]!=0) //表示有路 { if(maxPath[v1]+e[v1][v2]>maxPath[v2]) maxPath[v2]=maxPath[v1]+e[v1][v2]; if(maxPath[v2]>max) { max=maxPath[v2];//保存长度 path[v1][v2]=max; } }}}//求最长路线 stack<int> s;//保存线路for(i=vSize-1;i>0;){for(j=0;j<vSize;j++){p[j]=path[j][i]; }sort(p,p+vSize);int maxValue=p[j-1];if(maxValue!=0) { for(j=0;j<vSize;j++){ if(path[j][i]==maxValue){ s.push(i); i=j; if(i==0) s.push(i); break;} }}}//输出结果cout<<endl<<"最长路径的长度是:"<<max<<endl<<"最长路径为:";int len=s.size();for(i=0;i<len;i++){if(i!=0) cout<<" -> "; cout<<v[s.top()]; s.pop();}cout<<endl<<endl;}int main(){int vSize,eSize,i;while(1){cout<<"·请分别输入有向无环图的顶点数和边数:";cin>>vSize>>eSize; creatGraph(vSize,eSize);//创建图 topologicalSort(vSize);//拓扑排序getMaxPath(vSize);//最长路径}return 0;}
欢迎大家交流~
- C++之求有向无环图的最长路径(拓扑排序+动态规划)
- C++之求有向无环图的最长路径(拓扑排序+动态规划)
- 动态规划求有向无环图的最短路径
- 图之有向无环图,拓扑排序,关键路径
- 有向无环图的单源最短路径----拓扑排序+松弛
- C语言实现有向无环图的拓扑排序算法
- 有向无环图(AOE)的拓扑排序和关键路径
- 笔试题:动态规划之求数组中的最长路径
- 有向无环图的拓扑排序
- 有向无环图的拓扑排序
- 有向无环图的拓扑排序
- 【图论】有向无环图的拓扑排序
- 有向无环图- CSU1804(拓扑排序)
- 求以邻接矩阵存储的有向无环图中的最长路径
- 动态规划解——有向图中的最长路径
- 动态规划解——有向图中的最长路径
- 动态规划解——有向图中的最长路径
- 动态规划解——有向图中的最长路径
- in/ld: cannot find -lst/usr/bdc++
- Codefoces 432 C. Prime Swaps
- 链栈的c语言实现
- Hash算法简介
- Linux设备模型
- C++之求有向无环图的最长路径(拓扑排序+动态规划)
- sybase数据表的导出与导入
- umask
- 使用eclipse编译含有C++11特性的代码
- OpenCV中的Mat阵列操作
- 流行移动应用自动化测试开源框架/工具之优劣势比较
- jquery 选择器 之 nth-child
- 周报(第七周)
- csu(背包的变形题)