图论 —— DAG 图的最长路
【概述】
DAG 图的最长路问题是一个比较少见的问题,具体问题是:给出一个 DAG 图,寻找图中的最长路
在 AOE 网中,在找出关键路径后,对其进行 DFS 即可得到图的最长路,由于这种方法的实现过于繁琐,这里介绍几种较为简单的实现。
【最短路算法】
对于最短路算法,Floyd,Dijkstra、Bellman-Ford、SPFA 等,将其松弛操作进行修改,即可将最短路算法变为最长路算法。
以 Floyd 为例:
int G[N][N];
void Floyd(){for(int k=1;k<=n;k++)for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(i!=k&&j!=i&&j!=k)if(g[i][j]<g[i][k]+g[k][j])g[i][j]=g[i][k]+g[k][j];
}
int main(){int n,m;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%d",&g[i][j]);Floyd();int res=-INF;for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)res=max(g[i][j],res);printf("%d\n",res);return 0;
}
【拓扑排序】
在拓扑排序的过程中,不断记录路径,最后对路径进行排序,输出最大的那个即为 DAG 的最长路
struct Node{int to,dis;Node(){}Node(int to,int dis):to(to),dis(dis){}
};
vector<Node> G[N];
int in[N];
int dis[N];
int n,m;
void topSort() {stack<int > S;for(int i=1; i<=n; i++)if(!in[i])S.push(i);while(!S.empty()) {int x=S.top();S.pop();for(int j=0; j<G[x].size(); j++) {int y=G[x][j].to;dis[y]=max(dis[y],dis[x]+G[x][j].dis);in[y]--;if(!in[y])S.push(y);}}
}int main() {int T;scanf("%d",&T);while(T--){scanf("%d%d",&n,&m);memset(in,0,sizeof(in));memset(dis,0,sizeof(dis));for(int i=0; i<=n; i++)G[i].clear();for(int i=1; i<=m; i++) {int x,y,dis;scanf("%d%d%d",&x,&y,&dis);Node temp;temp.to=y;temp.dis=dis;in[y]++;G[x].push_back(temp);}topSort();int res=-INF;for(int i=1;i<=n;i++)res=max(res,dis[i]);printf("%d\n",res);}return 0;
}
【动态规划】
1.不固定终点起点
当给定一个 DAG 图时,要求整个图中所有路径中权值和最大的那条,即不固定终点和起点问题。
设 dp[i] 为从 i 点出发能获得的最长路径长度,G[i][j] 为从 i 点到 j 点的距离,这样所有的 dp[i] 的最大值就是整个 DAG 的最长路径长度,如果从 i 点出发,能直接到达顶点 j1、j2、...、jk,而 dp[j1]、dp[j2]、...、dp[k] 均已知,那么有:dp[i]=max{ dp[j]+G[i][j] }
根据上面的思路,由于最后的顶点没有出边,因此需要按照逆拓扑排序来求解 dp 数组,但可以利用递归来进行求解:由于从出度为 0 的顶点出发的最长路径长度为 0,因此边界就是这些点,在具体实现中不妨对整个 dp 数组初始化为 0,这样 DP 函数当前访问顶点i的出度为0时就会直接返回 dp[i]=0,而出度不为 0 的时候就会递归求解,递归过程中遇到已经计算过的顶点则直接返回对于的 dp 值,于是从逻辑上实现了逆拓扑排序的效果。
其基于邻接矩阵实现的代码如下:
int dp[N];//使用前整个数组设为0
int G[N][N];
int DP(int i) {if(dp[i]>0)return dp[i];for(int j=0; j<n; j++)//遍历i的所有可达出边if(G[i][j]!=INF)dp[i]=max(dp[i],DP(j)+G[i][j]);return dp[i];
}
当需要输出这条最长路时,可以利用一个 next 数组来记录 i 顶点的后继结点,再求完最长路后,顺序打印路径即可
int DP(int i) {if(dp[i]>0)return dp[i];for(int j=0; j<n; j++) { //遍历i的所有可达出边if(G[i][j]!=INF) {int temp=DP(j)+G[i][j];//单独计算dpif(dp[i]<temp) { //可以获得更长的路径dp[i]=temp;next[i]=j; //保存i的后继顶点j}}}return dp[i];
}
void printPath(int i) {//调用前需先获得最大的dp[i],然后将i作为路径的起点传入printf("%d",i);while(next[i]!=-1) { //next数组初始化为-1i=next[i];printf("->%d",i);}printf("\n");
}
2.固定终点起点
给定一个 DAG 图,给出一个起点和终点,要求从起点到终点的路径中权值和最大的那条,即固定终点和起点问题。
设规定的终点为 T,那么设 dp[i] 为从 i 号点出发到达终点 T 所能获得的最大长度,G[i][j] 为从 i 点到 j 点的距离,如果从 i 点出发,能直接到达顶点 j1、j2、...、jk,而 dp[j1]、dp[j2]、...、dp[k] 均已知,那么有:dp[i]=max{ dp[j]+G[i][j] }
可以发现,这个 dp 式子与上面不固定终点起点的问题相同,但问题的区别在于边界:
第一个问题中,没有固定的终点,因此边界为所有出度为 0 的顶点,其 dp 值为 0
第二个问题中,固定了终点,因此边界应当为 dp[T]=0,需要注意的是,由于从某顶点出发可能会无法到达终点 T,因此此时 dp 数组不能再全部初始化为 0,比较合适的做法是将 dp 初始化为一个极大的负数(-INF),来表达无法到达终点,然后设置一个 vis 数组来表示顶点是否已被访问
int vis[N];
int G[N][N];
int dp[N];//使用前初始化为-INF,且终点dp[T]=0
int DP(int i) {if(vis[i]) return dp[i];vis[i]=true;for(int j=0; j<n; j++) { //遍历i的所有可达出边if(G[i][j]!=INF) {dp[i]=max(dp[i],DP(j)+G[i][j]);}}return dp[i];
}
【例题】
- Find the safest road(HDU-1596)(Floyd 变形求最长路):点击这里
- 矩形嵌套(NYOJ-16)(dp 求最长路):点击这里
- Skiing(2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛 H)(拓扑排序求最长路):点击这里
图论 —— DAG 图的最长路相关推荐
- C - Coolest Ski Route(关于DAG图的最长路问题四种解法)
VJ链接 C - Coolest Ski Routehttps://vjudge.net/contest/491449#problem/C 首先是比赛中用的bfs写法 #include<iost ...
- 洛谷P1807 最长路_NOI导刊2010提高(07) 求有向无环图的 最长路 图论
洛谷P1807 最长路_NOI导刊2010提高(07) 图论 求有向无环图的 最长路 首先阐明一点 最长路dijkstra 是不能做 (当然我是不会做的,不过我貌似看到过网上的dalao有用dijst ...
- nyoj 10 skiing(DAG上的最长路,备忘录方法)
skiing 时间限制:3000 ms | 内存限制:65535 KB 难度:5 描述 Michael喜欢滑雪百这并不奇怪, 因为滑雪的确很刺激.可是为了获得速度,滑的区域必须向下倾斜,而且当你滑 ...
- HDU 4562 守护雅典娜(DAG上的最长路)
理解错题意了...写的很麻烦,而且900+卡过... 1 #include <iostream> 2 #include <cstdio> 3 #include <cstr ...
- 计蒜客-2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛H题Skiing(拓扑序求DAG最长路)
题意: 给定一个有向无环图,求该图的最长路. 思路: 由于是有向无环图,所以最长路肯定是一个入度为0到出度为0的路径,拓扑序在确定当前点之前能够考虑到所有到它的情况,所以最后取个最值即可. 代码: # ...
- 算法提高课-图论-单源最短路的建图方式-AcWing 1126. 最小花费:dijkstra求最长路
题目分析 来源:acwing 分析: 链条转移:start * (1-w1) * (1- w2) * (1- w3) -(1-wn) = 100,要start最小,则w =(1-w1) * (1- w ...
- 【EOJ Monthly 2019.02 - E】中位数(二分 ,中位数 ,−1/1变换,dp求解DAG最长路)
题干: E. 中位数 单测试点时限: 10.0 秒 内存限制: 256 MB "你的地图是一张白纸,所以即使想决定目的地,也不知道路在哪里." QQ 小方最近在自学图论.他突然想出 ...
- POJ - 3160 Father Christmas flymouse DAG最长路
又来做这一道缩点的裸题,发现图转化为DAG后明显是一个最长路,那么有没有固定都求法呢,查询资料后发现的确是一种固定的做法. DAG最长路,分为两种固定终点和不固定终点. 令dp[i]表示从i顶点出发能 ...
- (dag模型+最长路+字典序)嵌套矩形
题目: 有 n 个矩形,每个矩形可以用两个整数 a, b 描述,表示它的长和宽.矩形 X(a, b) 可以嵌套在矩形 Y(c, d) 中当且仅当 a<c, b<d,或者 b<c, a ...
最新文章
- 泛型委托Action与ActionT
- mongodb 输出数组字段_MongoDb文档操作、索引操作
- mysql的ps.setmaxrows_mysql自定义函数实现表的指定列进行数据脱敏(PS:来自mysql小白的提问)...
- 高中计算机编辑程序,高中信息技术信息的编程加工教案
- 逆天!百度AI音箱重磅升级:最大梦想实现
- 对null值的小知识
- linux cp 复制目录下文件到另一个目录下
- 【云计算学习教程】云计算虚拟化技术和容器技术详解
- 电脑共享打印机拒绝访问要怎么办
- Krytox VPF1525 VPF1514 VPF1506 XP Chemours DuPont
- 虚拟机安装win7 64位教程
- python使用openpyxl插入excel批注,同时修改excel批注框大小
- 学电力好还是计算机好,毕业后想进电力系统上班?这三个专业可优先考虑
- 聚合支付服务商“利楚扫呗”完成5000万元A轮融资 富友集团领投
- 武汉大学计算机学院夏桂松,实验室硕士研究生王碧杉、何敬伟在ECCV上发表事件相机高质量图像重建论文...
- mysql压缩包安装设置密码
- 图注意力网络(GAT)
- springMVC @initBinder 使用
- 游戏服务器多钱一个月呢?
- javascript思想干货
热门文章
- 这10个功能模块,手把手教你从零设计电商系统
- 入门干货:Python操作Word文件经验分享
- 如何领导团队做好技术债管理?
- 美团技术:交易平台建设实践(视频+胶片)
- jeecg 数据修改历史日志对比方法
- Hadoop框架:DataNode工作机制详解
- Java描述设计模式(03):工厂方法模式
- Spring MVC 实践 - Base
- 步步为营 .NET三层架构解析 七、UI的设计(登陆页面、注册页页和添加部门页面)...
- 《DeepLearning.ai 深度学习笔记》发布,黄海广博士整理