图最长路径:深大数据结构期末考上机题3
题目是这样的: 有一无向图,用邻接表存储,求从5顶点出发到各个顶点的最长路径长度,输出 最长路径长度 和 最长路径
偷偷把草稿纸带出来的屑
输入:
顶点数
边数
边
样例输入:
8
13
0 2 0.26
1 3 0.29
3 6 0.52
3 7 0.39
4 0 0.38
4 7 0.37
5 1 0.32
5 4 0.35
5 7 0.28
6 0 0.58
6 2 0.4
6 4 0.93
7 2 0.34
样例输出:
5->0 length is 2.44 path is: 5 1 3 6 4 0
5->1 length is 0.32 path is: 5 1
5->2 length is 2.77 path is: 5 1 3 6 4 7 2
5->3 length is 0.61 path is: 5 1 3
5->4 length is 2.06 path is: 5 1 3 6 4
5->6 length is 1.13 path is: 5 1 3 6
5->7 length is 2.43 path is: 5 1 3 6 4 7
(OJ当天就关了我也不知道上面的自制样例是不是真的正确)
当时卡了好一会,后来改出来了,我是用迪杰斯特拉做的,这里迪杰斯特拉要改几条语句,否则路径不对,然后后面问了下大佬,说是关键路径做的
迪杰斯特拉改的关键
关键就是迪杰斯特拉更新节点 i 的时候要重置 i 节点的路径的访问标志数组,也就是 visited[i] = 0 然后需要多更新一次,因为这一次更新的路径(起点到i)必然作为下一次更新时选择的候选路径,图解原因如下:
大致思路
- 将已知的最长的,未被选择过的路径 p_max 的终点 max_index 这个节点,作为更新的点
- 看是否有路径从 max_index 顶点出发,到 j 顶点的路径长度 :length(max_index -> j) + length(起点 -> max_index) 大于已知的到达 j 顶点的路径长度:length(起点 -> j)
即
length(max_index -> j) + length(起点 -> max_index) > length(起点 -> j) ?
访问重置 的解释
- 如果更新成功,新路径长度一定大于我们选择的路径的长度,因为多加了一条边(没有负权边)
- 现在选择的路径已经是已知路径中最长的了,新路径长于现在选择的路径,那么新路径一定是下一次选择最长已知路径中的备选方案,所以visited[]标志要置零
(或者这么理解:假设之前我们有一条A到C点的路径:
[A B C] 叫做 p1,我们认为它是最长的,我们用 p1 更新了A到F,G点的路径,但是现在发现了更长的A到C的路径:
[A D C] 叫做 p2,那么意味着从A到F,G点的路径有了更好的解,所以下一次应该基于 [A D C] 这条路径去更新F,G,但是因为在这之前已经基于 [A D C] 更新过到F,G的路径,visited[C] = 1,所以为了能够再次更新,需要重置标志)
多更新一次 的解释
- visited 标志置零说明总的更新次数要比预计的多选一次,故最外圈循环多一次,即 k = k - 1
更新最长路径的代码:
class edge
{
public:
edge();
int v2; // 边指向的顶点
double weight; // 边权值
};
#define maxlen 1009
deque<edge> adj[maxlen]; // 邻接表,edge 是边的类,包含顶点,权值成员
int visited[maxlen]; // visited[i]:起点到 i 节点的路径是否已经被选择过
double path[maxlen]; // path[i]:起点到 i 节点的最长路径长度
node PATH[maxlen]; // PATH[i]:链表保存起点到 i节点的最长路径
int n; // 顶点
int e; // 边
int i, j, k;
// 迪杰斯特拉 改
for(k=0; k<n; k++)
{
// 选择未被选择过的最长的一条路径
double max = -1145141919;
int max_index = 0;
for(i=0; i<n; i++)
{
if(path[i]>max && visited[i]==0