图最长路径:深大数据结构期末考上机题3

图最长路径:深大数据结构期末考上机题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)
		{
			max = path[i];
			max_index = i;
		}
	}
	visited[max_index] = 1;
	
	// 从 max_index 顶点出发更新最长路径 
	deque<edge>::iterator iter;
	for(iter=adj[max_index].begin(); iter!=adj[max_index].end(); iter++)
	{
		double weight = iter->weight;
		int v2 = iter->v2;
		
		if(weight+max > path[v2])
		{
			path[v2] = weight + max;
			PATH[v2] = *(PATH[max_index].cpy());
			PATH[v2].insert(v2);
			
			// 关键:下次可选 + 多选一次 
			visited[v2] = 0;
			k -= 1;
		}
	}
}

完整代码:

#include <iostream>
#include <deque>
#include <cstring>

using namespace std;

// class edge
class edge
{
public:
	edge();
	int v2;			// 边指向的顶点 
	double weight;	// 边权值 
};

edge::edge()
{
	
}
// end of class edge

// class node
class node
{
public:
	node();
	node* next;
	int data;
	
	void insert(int dt);
	node* cpy();	
	void out();
};

node::node()
{
	this->next = NULL;
}

// 表尾插入 
void node::insert(int dt)
{
	node* nd = new node();
	nd->data = dt;
	
	node* p = this;
	while(p->next)
	{
		p = p->next;
	}
	
	p->next = nd;
}

// 复制一份自己 
node* node::cpy()
{
	node* nd = new node();
	
	node* p = this->next;
	while(p)
	{
		nd->insert(p->data);
		p = p->next;
	}
	
	return nd;
}

void node::out()
{
	node* p = this->next;
	
	while(p)
	{
		cout<<p->data<<" ";
		p = p->next;
	}
}
// end of class node

#define maxlen 1009
deque<edge> adj[maxlen];	// 邻接表 
int visited[maxlen];	// 边的访问控制数组 
double path[maxlen];	// path[i]:通向 i 节点的最长路径长度 
node PATH[maxlen];	// PATH[i]:保存通向i节点的最长路径 

int n;	// 顶点 
int e;	// 边 
int i, j, k;

int main()
{
	cin>>n>>e; 
	
	memset(visited, 0, sizeof(visited));
	memset(path, (double)0.0, sizeof(path));
	
	// 读取边 
	for(i=0; i<e; i++)
	{
		int v1, v2;
		double w;
		cin>>v1>>v2>>w;
		
		edge* new_e = new edge();
		new_e->v2 = v2;
		new_e->weight = w;
		
		adj[v1].push_back(*new_e);
	}
	
	// 起点的直连路径 初始化 
	#define start 5	
	deque<edge>::iterator iter;
	for(iter=adj[start].begin(); iter!=adj[start].end(); iter++)
	{
		int v2 = iter->v2;
		double weight = iter->weight;
		path[v2] = weight;
		
		PATH[v2].insert(v2);
	}
	
	// 迪杰斯特拉 改 
	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)
			{
				max = path[i];
				max_index = i;
			}
		}
		visited[max_index] = 1;
		// cout<<"select "<<max_index<<" "<<max<<endl;
		
		// 从 max_index 顶点出发更新最长路径 
		deque<edge>::iterator iter;
		for(iter=adj[max_index].begin(); iter!=adj[max_index].end(); iter++)
		{
			double weight = iter->weight;
			int v2 = iter->v2;
			
			if(weight+max > path[v2])
			{
				path[v2] = weight + max;
				PATH[v2] = *(PATH[max_index].cpy());
				PATH[v2].insert(v2);
				
				// 关键:下次可选 + 多选一次 
				visited[v2] = 0;
				k -= 1;
			}
		}
	}
	
	// 输出 
	for(i=0; i<n; i++)
	{
		if(i != start)
		{
			cout<<start<<"->"<<i<<" length is "<<path[i]<<"  path is: "<<start<<" ";
			PATH[i].out();
			cout<<endl;
		}
	}
	
	return 0;
}

/*
sample input :
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
*/


发布了18 篇原创文章 · 获赞 0 · 访问量 138

猜你喜欢

转载自blog.csdn.net/weixin_44176696/article/details/103702187