【概述】

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 图的最长路相关推荐

  1. C - Coolest Ski Route(关于DAG图的最长路问题四种解法)

    VJ链接 C - Coolest Ski Routehttps://vjudge.net/contest/491449#problem/C 首先是比赛中用的bfs写法 #include<iost ...

  2. 洛谷P1807 最长路_NOI导刊2010提高(07) 求有向无环图的 最长路 图论

    洛谷P1807 最长路_NOI导刊2010提高(07) 图论 求有向无环图的 最长路 首先阐明一点 最长路dijkstra 是不能做 (当然我是不会做的,不过我貌似看到过网上的dalao有用dijst ...

  3. nyoj 10 skiing(DAG上的最长路,备忘录方法)

    skiing 时间限制:3000 ms  |  内存限制:65535 KB 难度:5 描述 Michael喜欢滑雪百这并不奇怪, 因为滑雪的确很刺激.可是为了获得速度,滑的区域必须向下倾斜,而且当你滑 ...

  4. HDU 4562 守护雅典娜(DAG上的最长路)

    理解错题意了...写的很麻烦,而且900+卡过... 1 #include <iostream> 2 #include <cstdio> 3 #include <cstr ...

  5. 计蒜客-2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛H题Skiing(拓扑序求DAG最长路)

    题意: 给定一个有向无环图,求该图的最长路. 思路: 由于是有向无环图,所以最长路肯定是一个入度为0到出度为0的路径,拓扑序在确定当前点之前能够考虑到所有到它的情况,所以最后取个最值即可. 代码: # ...

  6. 算法提高课-图论-单源最短路的建图方式-AcWing 1126. 最小花费:dijkstra求最长路

    题目分析 来源:acwing 分析: 链条转移:start * (1-w1) * (1- w2) * (1- w3) -(1-wn) = 100,要start最小,则w =(1-w1) * (1- w ...

  7. 【EOJ Monthly 2019.02 - E】中位数(二分 ,中位数 ,−1/1变换,dp求解DAG最长路)

    题干: E. 中位数 单测试点时限: 10.0 秒 内存限制: 256 MB "你的地图是一张白纸,所以即使想决定目的地,也不知道路在哪里." QQ 小方最近在自学图论.他突然想出 ...

  8. POJ - 3160 Father Christmas flymouse DAG最长路

    又来做这一道缩点的裸题,发现图转化为DAG后明显是一个最长路,那么有没有固定都求法呢,查询资料后发现的确是一种固定的做法. DAG最长路,分为两种固定终点和不固定终点. 令dp[i]表示从i顶点出发能 ...

  9. (dag模型+最长路+字典序)嵌套矩形

    题目: 有 n 个矩形,每个矩形可以用两个整数 a, b 描述,表示它的长和宽.矩形 X(a, b) 可以嵌套在矩形 Y(c, d) 中当且仅当 a<c, b<d,或者 b<c, a ...

最新文章

  1. 泛型委托Action与ActionT
  2. mongodb 输出数组字段_MongoDb文档操作、索引操作
  3. mysql的ps.setmaxrows_mysql自定义函数实现表的指定列进行数据脱敏(PS:来自mysql小白的提问)...
  4. 高中计算机编辑程序,高中信息技术信息的编程加工教案
  5. 逆天!百度AI音箱重磅升级:最大梦想实现
  6. 对null值的小知识
  7. linux cp 复制目录下文件到另一个目录下
  8. 【云计算学习教程】云计算虚拟化技术和容器技术详解
  9. 电脑共享打印机拒绝访问要怎么办
  10. Krytox VPF1525 VPF1514 VPF1506 XP Chemours DuPont
  11. 虚拟机安装win7 64位教程
  12. python使用openpyxl插入excel批注,同时修改excel批注框大小
  13. 学电力好还是计算机好,毕业后想进电力系统上班?这三个专业可优先考虑
  14. 聚合支付服务商“利楚扫呗”完成5000万元A轮融资 富友集团领投
  15. 武汉大学计算机学院夏桂松,实验室硕士研究生王碧杉、何敬伟在ECCV上发表事件相机高质量图像重建论文...
  16. mysql压缩包安装设置密码
  17. 图注意力网络(GAT)
  18. springMVC @initBinder 使用
  19. 游戏服务器多钱一个月呢?
  20. javascript思想干货

热门文章

  1. 这10个功能模块,手把手教你从零设计电商系统
  2. 入门干货:Python操作Word文件经验分享
  3. 如何领导团队做好技术债管理?
  4. 美团技术:交易平台建设实践(视频+胶片)
  5. jeecg 数据修改历史日志对比方法
  6. Hadoop框架:DataNode工作机制详解
  7. Java描述设计模式(03):工厂方法模式
  8. Spring MVC 实践 - Base
  9. 步步为营 .NET三层架构解析 七、UI的设计(登陆页面、注册页页和添加部门页面)...
  10. 《DeepLearning.ai 深度学习笔记》发布,黄海广博士整理