请编写程序求给定正权有向图的单源最短路径长度。图中包含n个顶点,编号为0至n-1,以顶点0作为源点。
输入格式:
输入第一行为两个正整数n和e,分别表示图的顶点数和边数,其中n不超过20000,e不超过1000。接下来e行表示每条边的信息,每行为3个非负整数a、b、c,其中a和b表示该边的端点编号,c表示权值。各边并非按端点编号顺序排列。
输出格式:
输出为一行整数,为按顶点编号顺序排列的源点0到各顶点的最短路径长度(不含源点到源点),每个整数后一个空格。如源点到某顶点无最短路径,则不输出该条路径长度。
输入样例:
4 4
0 1 1
0 3 1
1 3 1
2 0 1
输出样例:
1 1
解题思路:
1.求单源最短路径问题考虑用Dijkstra算法。
2.本题节点数过多,图过大,用邻接矩阵会段错误,所以用邻接表。
3.定义一个int dist[]用来储存源点到各点的最短距离,初始化为0;定义一个int visit[]来判断是否已经找到源点到该点的最短路径。
4.建立好邻接表后先将源点能够直接到达的点和距离添加到dist[]中。每次从中找到最短的一条,并靠该点的信息更新dist[];
代码如下:
#include<bits/stdc++.h>
using namespace std;
//data为到达的点,weight为到达该点的距离。
struct vertex{
int data,weight;
vertex* next;
};
//dist[]数组用来存储源点到各点的最短距离,visit[]用来标记是否找到了从源点到该点的最短距离。
int dist[20005],visit[20005];
//创建图
struct {
int numv, nume;
vertex vertices[20005];
}G;
//输入边的信息,构建图
void join() {
int x, y;
cin >> x >> y;
vertex* t=new vertex;
t->data = y;
cin >> t->weight;
t->next = G.vertices[x].next;
G.vertices[x].next = t;
}
//找到dist[]中最小的一条边,返回下标
int findmin(){
int min = INT_MAX;
int index = -1;
for (int i = 0; i < G.numv; ++i) {
//要注意dist【i】不能等于0(因为等于0表示没有边),且visit[i]==0(表示没有被找到最短距离的点)
if (dist[i] < min&&visit[i]==0&&dist[i]!=0) {
min = dist[i];
index = i;
}
}
return index;
}
void Dijkstra() {
//源点不用找,所以要找G.numv-1个点加入进去
int N=G.numv-1;
//源点已经被找到
visit[0] = 1;
while (N-->0) {
int a = findmin();
//当a==-1的时候就说明dist中已经没有满足dist[i]!=0(有边)&&visit[i]==0(没被访问)的点了;
//这时候就直接不用找了,break.
if(a==-1)break;
//能找到就把这个点标记
visit[a] = 1;
//找这个新加入的点,是否会令源点到达其他点的距离更短
//因为该邻接表储存的出度,所以到这个点的链表中找,t->data是从这个点到达的其他点,如果(源点到其他点的距离>源点到该点的距离+该点到其他点的距离)||(源点到不了该点)那么就更新;
vertex* t = G.vertices[a].next;
while (t != NULL) {
//如果
if (dist[t->data] > (dist[a] + t->weight) || dist[t->data] == 0) {
dist[t->data] = dist[a] + t->weight;
}
t=t->next;
}
}
}
int main() {
cin >> G.numv >> G.nume;
//初始化,可有可无
for (int i = 0; i < G.numv; ++i) {
G.vertices[i].data = i;
G.vertices[i].next = NULL;
}
//加入边,构建图
while (G.nume--) {
join();
}
//初始化源点能够直接到达的距离;
vertex* head = G.vertices[0].next;
while (head!=NULL) {
dist[head->data] = head->weight;
head = head->next;
}
Dijkstra();
//输出,注意这里必须i=1,不能写i=0;因为他有可能给0 0 5这种边,下面的话写if(dist[i]!=0)cout的话到他本身会输出5,这里直接把到它本身跳过去就行了.好恶心!!!!
for (int i = 1; i < G . numv; ++i) {
if(dist[i]!=0)cout << dist[i] << " ";
}
return 0;
}