学成区间DP回答群友的问题——多段图最短路径问题|刷题打卡

357 阅读1分钟

一、题目描述:

设图 G =(V,E)是一个带权有向图,如果把顶点集合 V 划分成 k 个互不相交的子集 Vi(2<=k<=n,1<=i<=k),使得 E 中的任何一条边 <u,v>,必有 u∈Vi, v∈Vi + m(1<=i<k, 1<i+m<=k),则称图 G 为多段图,称 s∈V1 为源点,t∈Vk 为终点。多段图的最短路径问题为从源点到终点的最小代价路径。

二、思路分析:

这道题我们用昨天讲的区间DP的思路去做,

第一维是枚举区间长度:那么区间很明显是2-段数量.

第二维枚举起点 i : int l = i, r = l + len - 1;

最后枚举分割点k

有状态转移方程

for(int k = l; k < r; k ++ )
dp[l][r] = min(dp[l][k] + dp[k + 1][r], dp[l][r]);

三、AC 代码:

因为没有给输入输出,这里也没有确切的代码,只能说猜个输入输出

1. vector<vector<int>> edges;
// 一个二维数组,其中edges.size 为边的数量, edges[0].size == 3
// 前两个值为 起点和重点 第三个值为边的距离
2. vector<vector<int>> duan;
// 同一行的点为同一段

写道这里我们发现前面写的不对了,因为

  1. dp[l][l]是无意义的
  2. dp[l][r] 不能用 dp[l][k] + **dp[k + 1][r]**表达,而是dp[l][r] = dp[l][k] + dp[k][r]
  3. 由于多段图,因此只有相邻段才可以抵达
for(int i = 0; i < edges.size(); i++){
	int l = edges[i][0];
    int r = edges[i][1];
    dp[l][r] = edges[i][2];
}//把边的值放入dp中
map<int,int> hp;
int N; // 点的个数
for(int i = 0; i < duan.size(); i ++){
	for(int j = 0; j < duan[i].size(); j ++){
		hp[duan[i][j]] = i; 
        N++;
	}
}
// 用来判断 两个点是否同一段

for(int len = 2; len < N; len ++){
	for(int i = 1; i + len <= N; i++){
    	int l = i, r = len + i;
        for(int k = i + 1; k < r; k ++){
			if(dp[l][r] == 0) dp[l][r] = dp[l][k] + dp[k][r];
            dp[l][r] = min(dp[l][k] + dp[k][r], dp[l][r]);
        }
        
    }
}
return dp[1][N];

四、总结:

其实看到群友问这道问题的时候,我还没学区间DP,美中不足这道题并不是LC的题,没法提交代码看看对不对(毕竟我提交记录向来都是一堆错误,害慢慢改被)。

如果有在哪个做题平台上看到这道题的,麻烦评论区告诉我下,我可以完善下代码。

本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情