DAG最长路(最短路)

DAG就是有向无环图。

DAG上的最长或者最短路是很重要的一类问题。很多问题都可以转化为DAG上的最长或者最短路径的问题。DAG求最短和最长路的方法一样。

本算法主要解决2个问题

1)求整个DAG中的最长路径(即不固定起点,也不固定终点)

2)固定终点,求DAG的最长路径。

1)求整个DAG中的最长路径(即不固定起点,也不固定终点)

dp【i】表示从 i 号顶点出发能获得的最长路径的长度

int DP(int i){
	if(dp[i] > 0){
		return dp[i];
	}
	for(int j = 0; j < n; j++){
		if(G[i][j] != INF){
			dp[i] = max(dp[i], DP(j) + G[i][j]);    //状态方程
		}
	}
	return dp[i];
}

入度为0的顶点出发最长路径长度就0,这就递归边界。

但是我们实际写的时候不妨对整个dp数组进行初始化为0,这样当dp函数访问的顶点i的出度为0的时候就会返回值0.(以此作为递归边界)。而出度不为0的就会自动递归求解。递归过程中,遇到已经计算过的顶点则直接返回对应的dp值,于是从程序逻辑上按照逆拓扑排序进行。

求路径

int DP(int i){
	if(dp[i] > 0) return dp[i];
	for(int j = 0; j < n; j++){
		if(G[i][j] != INF){
			int temp = DP(j) + G[i][j];	//单独计算以防调用Dp函数2次。 
			if(temp > dp[i]){
				dp[i] = temp;
				choice[i] = j; 	//j是i的后继 
			}
		}
		return dp[i];
	}
}

void printPath(int i){
	printf("%d", i);
	while(choice[i] != -1){
		i = choice[i];
		printf("->%d", i);
	}
}

如果有多条路径开个vector数组即可,并且 这个是自动按字典序最小输出的。因为你循环的时候是从小到大循环找路径的

至此,零dp【i】 表示从i 顶点出发的最长路径已经求出来了。那么以i顶点结尾的最长路径长度怎么求呢?

2)固定终点,求DAG的最长路径。

可以想象只要把求解公式变一下就可以了

dp[i] = max(dp[j] + G[j][i]);  

求解顺序变为拓扑排序

但是却不能直接得到字典序求出。

上面讨论的基础上,我们来讨论第二个问题,固定终点,求DAG的最长路径长度。假设终点为T,令dp【i】表示从i好顶点出发到达终点T能获得的最长路径长度。

那这与第一个有什么不同呢?

没错就是边界,第一求得边界是出度为0的点,dp值也为0,这个是求T点的DP值。

那么dp【T】  = 0

那么我们能不能还把其他的dp位置还设置为0呢?显然不行,因为由于冲没写顶点出发可能无法到达终点T,如果dp还是初始化为0那么就会得到错误的结果,我们应该初始化为-INF,如果是 +INF 会带来麻烦的(因为我们求的最长路)求最短路反之。

然后我们需要设置一个vis数组,表示这个顶点是否访问过

int DP(int i){
	if(vis[i]) return dp[i];
	vis[i] = true;
	for(int j = 0; j < n; j++){
		if( G[i][j] != INF){
			int temp = max (dp[i], DP(j) + G[i][j]);
			dp[i] = temp;
		}
	} 
	return dp[i];
} 

矩形嵌套问题:

 

最短路

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值