[模板]-单源最短路径
2017-08-19 11:22
393 查看
问题描述:
给出一个有向图,请输出从某一点出发到所有点的最短路径长度。
输入输出格式
输入格式:
第一行包含三个整数N、M、S,分别表示点的个数、有向边的个数、出发点的编号。
接下来M行每行包含三个整数Fi、Gi、Wi,分别表示第i条有向边的出发点、目标点和长度。
输出格式:
一行,包含N个用空格分隔的整数,其中第i个整数表示从点S出发到点i的最短路径长度(若S=i则最短路径长度为0,若从点S无法到达点i,则最短路径长度为2147483647)
代码①:邻接矩阵 + 裸迪杰斯特拉
算法的基本思想是:每次找到离源点最近的一个顶点,然后以该顶点为中转点进行扩展,最终得到源点到其余所有点的最短路径
代码②:邻接链表 + SPFA(贝尔曼-福德算法的队列优化)
![](https://img-blog.csdn.net/20170820151128832?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3VudGVuZ25i/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
算法的关键之处在于:只有那些在前一遍松弛中改变了最短路程估计值的顶点,才可能引起它们邻接点最短路程估计值发生改变
代码③:链式前向星 + 堆优化迪杰斯特拉:
对链式前向星不了解的朋友请看:http://blog.csdn.net/suntengnb/article/details/77450558
迪杰斯特拉算法步骤:
a.初始时,S只包含源点,即S={v},v的距离为0。U包含除v外的其他顶点,即:U={其余顶点},若v与U中顶点u有边,则
给出一个有向图,请输出从某一点出发到所有点的最短路径长度。
输入输出格式
输入格式:
第一行包含三个整数N、M、S,分别表示点的个数、有向边的个数、出发点的编号。
接下来M行每行包含三个整数Fi、Gi、Wi,分别表示第i条有向边的出发点、目标点和长度。
输出格式:
一行,包含N个用空格分隔的整数,其中第i个整数表示从点S出发到点i的最短路径长度(若S=i则最短路径长度为0,若从点S无法到达点i,则最短路径长度为2147483647)
代码①:邻接矩阵 + 裸迪杰斯特拉
#define inf 0x3f3f3f3f//0x7fffffff int mapp[1001][1001],book[1001],dis[1001],n;//标记数组book,距离数组dis,顶点数n void dijkstra(int x) { int Min,p; for(int i = 1; i <= n; i++)//初始化源点x到其余各个顶点的路程 dis[i] = mapp[x][i]; dis[x] = 0; book[x] = 1;//标记 for(int i = 1; i <= n - 1; i++)//只需要松弛n - 1轮 { Min = inf;//初始化最小值 for(int j = 1; j <= n; j++)//从各个顶点中找出 if(book[j] == 0 && Min > dis[j])没被标记过且距离源点最近的 { //更新 p = j; Min = dis[j]; } book[p] = 1;//找到了以后,标记该点 for(int j = 1; j <= n; j++)//以p点为中转点,进行松弛操作 if(book[j] == 0 && Min + mapp[p][j] < dis[j])//必须没被标记过 dis[j] = Min + mapp[p][j];//更新 } for(int i = 1; i <= n; i++)//按照题意输出 if(dis[i] == inf) printf("2147483647 "); else printf("%d ",dis[i]); printf("\n"); } int main() { int m,s,f,g,w; scanf("%d%d%d",&n,&m,&s);//n个顶点,m条边,查询s点 //初始化邻接矩阵 for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) if(i == j) mapp[i][j] = 0; else mapp[i][j] = inf; for(int i = 1; i <= m; i++) { scanf("%d%d%d",&f,&g,&w);//点f到点g权值为w if(f == g)//特判 continue;//防止数据有坑 if(w >= mapp[f][g])//不能使较大值将较小值覆盖 co f573 ntinue; mapp[f][g] = w;//没问题,放心赋值 } dijkstra(s);//调用 return 0; }
算法的基本思想是:每次找到离源点最近的一个顶点,然后以该顶点为中转点进行扩展,最终得到源点到其余所有点的最短路径
代码②:邻接链表 + SPFA(贝尔曼-福德算法的队列优化)
#define inf 0x3f3f3f3f//0x7fffffff int book[10001],dis[10001],n;//标记数组book,距离数组dis,顶点数n struct Node//结构体 { int v;//顶点编号 int w;//权值 struct Node* next;//后继指针 }; Node Head[10001];//最多1万个顶点 queue<int> que;//队列 void CreatGraph(int node1,int node2,int w)//顶点node1到顶点node2,权值为w { Node* pointer;//定义指针 Node* New;//定义指针 New = (Node*)malloc(sizeof(struct Node));//生成新结点 if(New != NULL)//如果成功 { New -> v = node2;//赋顶点编号 New -> w = w;//赋权值 New -> next = NULL;//将后继指针置为空 pointer = &(Head[node1]);//指向顶点node1 while(pointer -> next != NULL) pointer = pointer -> next; pointer -> next = New;//将node2与node1建立关系 } } void spfa(int x) { Node* pointer;//定义指针 que.push(x);//将源点入队 book[x] = 1;//标记源点已经入队 //初始化 for(int i = 1; i <= n; i++) dis[i] = inf; dis[x] = 0; while(!que.empty())//当队列不为空时进行循环 { int i = que.front(); pointer = &(Head[i]);//指向当前需要处理的队首顶点 while(pointer != NULL)//扫描当前顶点所有的边 { // 顶点x到顶点v 顶点x到顶点i 顶点i到顶点v的权值 if(dis[pointer -> v] > dis[i] + pointer -> w)//判断是否松弛成功 { dis[pointer -> v] = dis[i] + pointer -> w;//更新 if(book[pointer -> v] == 0);//如果顶点v不在队列中 { que.push(pointer -> v);//入队 book[pointer -> v] = 1;//标记 } } pointer = pointer -> next; } book[i] = 0;//取消标记 que.pop();//出队 } for(int i = 1; i <= n; i++)//按照题意输出 if(dis[i] == inf) printf("2147483647"); else printf("%d ",dis[i]); printf("\n"); } int main() { int m,s,f,g,w; scanf("%d%d%d",&n,&m,&s);//n个顶点,m条边,查询s点 for(int i = 1; i <= n; i++)//初始化邻接链表 { Head[i].v = i;//顶点的编号 Head[i].w = 0;//权值赋为0 Head[i].next = NULL;//后继指针赋为空 } Node* pointer;//定义一个指针 for(int i = 1; i <= m; i++) { scanf("%d%d%d",&f,&g,&w);//点f到点g权值为w if(f == g)//特判 continue;//防止数据有坑 pointer = &(Head[f]);//将指针指向顶点f //注意必须将pointer != NULL放在前面,防止发生未定义行为 while(pointer != NULL && pointer -> v != g)//查询是否已经与顶点g建立了关系 pointer = pointer -> next; if(pointer == NULL)//如果没有 CreatGraph(f,g,w); else if(pointer -> v == g && pointer -> w > w)//如果已经与顶点g建立了关系且输入的w比以往的w还小 pointer -> w = w;//就更新一下w else continue; } spfa(s);//调用 return 0; }
算法的关键之处在于:只有那些在前一遍松弛中改变了最短路程估计值的顶点,才可能引起它们邻接点最短路程估计值发生改变
代码③:链式前向星 + 堆优化迪杰斯特拉:
对链式前向星不了解的朋友请看:http://blog.csdn.net/suntengnb/article/details/77450558
typedef pair<int,int> Pair;//pair类型的使用比较繁琐,所以用typedef简化声明 priority_queue<Pair,vector<Pair>,greater<Pair> > pq;//小顶堆 struct Edge { int next;//edge[i].next表示与第i条边同起点的下一条边的存储位置 int to;//edge[i].to表示第i条边的终点 int w;//权值 }; Edge edge[500010];//注意要存成边的上限 int cnt = 1, head[10001],dis[10001],book[10001];//cnt从1开始,head[i]表示以i为起点的第一条边存储的位置,dis[i]表示源点到顶点i的最短距离,book数组用来标记 void AddEdge(int f,int g,int w)//增加一条边 { edge[cnt].next = head[f]; edge[cnt].to = g;//终点 edge[cnt].w = w;//权值 head[f] = cnt;//更新 cnt++;//自增 } void dijkstra_heap(int x)//堆优化的Dijkstra { dis[x] = 0;//初始化 pq.push(make_pair(dis[x],x));//将源点及其到自身的距离加入堆 while(!pq.empty())//当堆非空时进行循环 { Pair t = pq.top();//访问堆顶元素 pq.pop();//弹出堆 int point = t.second;//顶点编号 if(book[point] == 0)//如果没被标记 { book[point] = 1;//标记 for(int i = head[point]; i != -1; i = edge[i].next)//遍历以点point为起点的所有边,i为边的编号 // 源点x到第i条边的终点 源点到点point 点point到终点的权值 if(dis[edge[i].to] > dis[point] + edge[i].w) { dis[edge[i].to] = dis[point] + edge[i].w;//更新 pq.push(make_pair(dis[edge[i].to],edge[i].to));//将源点到终点的距离及终点加入堆 } } } } int main() { int n,m,s,f,g,w; scanf("%d%d%d",&n,&m,&s);//n个顶点,m条边,查询s点 memset(head,-1,sizeof(head));//初始化为-1 for(int i = 1; i <= n; ++i)//初始化为无穷大 dis[i] = inf; for(int i = 1; i <= m; i++) { scanf("%d%d%d",&f,&g,&w);//加入的边是共存的,不存在覆盖这一说法 AddEdge(f,g,w);//加入边 } dijkstra_heap(s);//调用 for(int i = 1; i <= n; i++)//按照题意输出 if(dis[i] == inf) printf("2147483647 "); else printf("%d ",dis[i]); printf("\n"); return 0; }
迪杰斯特拉算法步骤:
a.初始时,S只包含源点,即S={v},v的距离为0。U包含除v外的其他顶点,即:U={其余顶点},若v与U中顶点u有边,则
相关文章推荐
- 【模板】单源最短路径*
- [洛谷]P3371 单源最短路径模板-bell
- luoguP3371 【模板】单源最短路径
- [洛谷]P3371 单源最短路径模板 Dijkstra
- 单源最短路径Dijkstra、BellmanFord、SPFA【模板】
- hdu1874 畅通工程续 单源最短路径 模板题
- P3371 【模板】单源最短路径
- 【模板】 Dijkstra单源最短路径 (模板题:XJOI P1061)
- 普及练习场 普及常见模板 【模板】单源最短路径
- [模板]-单源最短路径-SPFA
- 【模板】Spfa单源最短路径
- 洛谷 P3371 【模板】单源最短路径
- P3371 【模板】单源最短路径
- 洛谷 P3371 【模板】单源最短路径
- P3371 【模板】单源最短路径
- luoguP3371 【模板】单源最短路径(SPFA)
- 单源最短路径模板整理
- luoguP3371【模板】单源最短路径(Dijkstra+优先队列优化)
- P3371 【模板】单源最短路径
- 【20171109】Luogu P3371 【模板】单源最短路径--SPFA