题意:两个整数:T和N.接下来T行,每行描述以三个以空格分隔的整数的轨迹。
前两个分别代表两个点,第三个为两点间的距离
输出:从N到1必须经过的最小距离
<3> 优先队列优化的djk求单源最短路,链式前向星存图 时间复杂度o(E * log(V))
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
typedef pair<int, int> pii; //first存储权值,second存储终点
const int N=1e5+10; //最大点数
const int maxn=1e6+10; //边的对数
const int INF=0x3f3f3f3f;
int n,m; //n是图中的点数,m是图中的边数
int head[N],top; //head[i]:记录以i为起点的最后一条边 top:记录边的输入,每输入一组top++
int dis[N]; //dis[i]:存储点i到起点的最短距离
void init(int n){ // 初始化
memset(head, -1, sizeof(int) * (n + 1));
top = 0;
}
struct Edge{ //边的定义
int to,val,next; //to:边的终点 val:权值 next:与该边同起点的上一条边的位置
Edge(){}
Edge(int _to,int _val,int _next){
to=_to; val=_val; next=_next;
}
}edge[maxn<<1]; //!!如果是双向图的话,边的数量是题目中描述的二倍
void Add(int u,int v,int val){ //添加单向边
edge[top]=Edge(v,val,head[u]);
head[u]=top++;
}
void getmap(int m){ //构图
int u,v,val;
while(m--){
scanf("%d %d %d",&u,&v,&val); //u->v有边
Add(u,v,val);
Add(v,u,val); //如果是无向图,就加上这个代码
}
}
void djk(int st,int ed){ //!!如果是双向图的话,边的数量是题目中描述的二倍
memset(dis,0x3f,sizeof(int) *(n+1));
priority_queue<pii,vector<pii>,greater<pii> > que; //优先队列由小到大排序默认写法
dis[st]=0; //起点到起点的距离为0
que.push(make_pair(0,st)); //make_pair(dis, v) 表示v到起点的距离为dis
while(!que.empty()){
pii p=que.top(); //每次取离起点最近的
que.pop();
int v=p.second; //v:边的终点
if(dis[v]<p.first) continue; //如果没有更优,跳过
for(int i=head[v];~i;i=edge[i].next){
Edge e=edge[i];
if(dis[e.to]>dis[v]+e.val){ //是否可以进行松弛
dis[e.to] = dis[v] + e.val;
que.push(make_pair(dis[e.to], e.to));
}
}
}
printf("%d\n", dis[ed] == INF ? -1 : dis[ed]);
}
int main(){
int t;
scanf("%d %d",&t,&n); //t为边数,n代表起点
init(n);
getmap(t);
djk(n,1); //n:起点 1:终点
return 0;
}