一、题目描述:
设图 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;
// 同一行的点为同一段
写道这里我们发现前面写的不对了,因为
- dp[l][l]是无意义的
- dp[l][r] 不能用 dp[l][k] + **dp[k + 1][r]**表达,而是dp[l][r] = dp[l][k] + dp[k][r]
- 由于多段图,因此只有相邻段才可以抵达
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 春招闯关活动」, 点击查看 活动详情