Description
给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。
Input Format
输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数 s,t;起点s,终点t。
(1<n<=1000, 0<m<100000, s != t)
Output Format
一行有两个数, 最短距离及其花费。
Sample Input
3 2
1 2 5 6
2 3 4 5
1 3
Sample Output
9 11
只是想重温一下Dijkstra算法的实现,但找来找去找不到简单的题目,于是取上面的这道题凑数,只是作为参考其输入输出格式,并不是要解答这道题。
dijkstra算法是计算某一个源点到其他所有顶点的最短路径,将顶点分成两个集合:
一个是集合Visited,代表这个集合中的顶点都已经找到其到源点的最短路径;
另一个是集合Unvisited,代表这个集合中的顶点到源点的最短路径尚未确定。
刚开始时将源点纳入集合Visited中,然后开始遍历Unvisited集合中的顶点(每次确定一个顶点的最短路径):
每一次遍历,都要找出Unvisited集合里面距离源点最近的那个顶点min_index,将其纳入Visited集合中,接着就是Dijkstra算法最重要的步骤所在:
设
s:源点;
min_index:刚刚被纳入Visited集合中的顶点;
i:当前遍历到的Unvisited集合中的顶点。
比较路径s-->(...)-->min_index-->i 的长度,是否比原先的路径s-->(...)-->i 要短,如果更短则作相应的修改.
具体思路和过程写在注释里:
#include <iostream>
#include <cstring>
#include <stack>
using namespace std;
const int MAXNUM=99999;
int main()
{
int n,m;//n个点,m条边
cin>>n>>m;
int edge[n+1][n+1];//点i到点j的边的距离,为MAXNUM表示不可达
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
edge[i][j]=MAXNUM;
for(int i=0;i<m;i++)
{
int a,b,d,p;
cin>>a>>b>>d>>p;//从点a到点b有无向边,其长度为d,费用为p
edge[a][b]=d;
edge[b][a]=d;
}
int s,t;//s为起点,t为终点
cin>>s>>t;
//dis[i]代表源点到点i的最短距离
//prev[i]表示源点到点i的最短路径中,点i的前一个结点 ,
// 可以借助这个数组一直溯源从而获得最短路径
//cost[i]代表源点到点i的费用
int dis[n+1],prev[n+1],cost[n+1];
for(int i=1;i<=n;i++) {
prev[i]=s;
}
for(int i=1;i<=n;i++){
dis[i]=edge[s][i];//初始化所有节点的dis[]数组为其到源点的距离
}
bool visited[n+1]; //visited[i]=1代表该点已找到最短路径
memset(visited,0,sizeof(visited));
visited[s]=1;
for(int i=1;i<=n;i++)
{
int min_index; //剩余的点中,到原点的距离最短的那个点
int min=MAXNUM;//剩余的点到原点的最短距离
for(int j=1;j<=n;j++)//找出剩余点中离原点最近的点
{
if(!visited[j]&&dis[j]<min)
{
min=dis[j];
min_index=j;
}
}
visited[min_index]=1;//表示这个点已经找到最短路径了
for(int j=1;j<=n;j++)
{
//遍历未访问过的点,如果从当前点min_index到该点v[j]的距离(即min+edge[j][min_index])
//比原本的dis[j]更短,则修改dis,且记录下修改后的路径path
if(!visited[j]&&min+edge[j][min_index]<dis[j])
{
dis[j]=dis[min_index]+edge[j][min_index];
prev[j]=min_index;
}
}
}
cout<<"从源点s到终点t的最短距离为"<<dis[t]<<endl;
cout<<"路径:";
stack<int> stk;
stk.push(t);
int tem=t;;
while(1){
tem=prev[tem];
stk.push(tem);
if(tem==s) break;
}
while(!stk.empty()){
cout<<stk.top()<<" ";
stk.pop();
}
}