今天刚学会Dijkstra算法的堆优化 练练手
洛谷 P1629 邮递员送信 题目链接
思路:
正着走过去的时候用一便dijkstra。
返回时就建个返图跑一遍dijkstra。
反图可以把所有结点的编号 +n建在原图的体系中。
dijkstra(1);
for(int i=1;i<=n;i++){
sum+=dist[i];
}
dijkstra(n+1);
for(int i=1+n;i<=n*2;i++){
sum+=dist[i];
}
完整代码:
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
const int N=510010;
typedef pair<int,int> PII;//<离起点的距离,节点编号>
int to[N],ne[N],w[N],idx;
int h[N];
int dist[N];
int st[N];
int n,m,start=1;
//在x节点之后插入一个y节点,权重为w
void add(int x,int y,int c){
w[idx]=c;
to[idx]=y;
ne[idx]=h[x];
h[x]=idx++;
}
int dijkstra(int start){
memset(dist,0x3f3f3f3f,sizeof dist);//所有距离初始化为无穷大
dist[start]=0;//start号节点距离为0
priority_queue<PII,vector<PII>,greater<PII> > heap;//建立一个小根堆 --优先队列
heap.push({0,start});//1号节点插入堆
while(heap.size()){
PII t=heap.top();//取出堆顶顶点
heap.pop();//并从堆中删除
int ver=t.second,distance=t.first; //取出节点编号和节点距离
if(st[ver])continue;//如果节点被访问过则跳过
st[ver]=true;
//遍历以ver为起始位置的所有边
for(int i=h[ver];i!=-1;i=ne[i]){
int j=to[i];//取出节点编号
if(distance+w[i]<dist[j]){
dist[j]=distance+w[i];
heap.push({dist[j],j});
}
}
}
// if(dist[n]==0x3f3f3f3f)return -1;
// return dist[n];
}
int main(){
int sum=0;
memset(h,-1,sizeof h);//将h[]数组初始化为-1
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
add(b+n,a+n,c);//!
}
dijkstra(1);
for(int i=1;i<=n;i++){
sum+=dist[i];
}
dijkstra(n+1);
for(int i=1+n;i<=n*2;i++){
sum+=dist[i];
}
// for(int i=1+n;i<=n*2;i++){
// sum+=dist[i];
// }
cout<<sum;
return 0;
}