洛谷 P1629 邮递员送信

今天刚学会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; 
}
上一篇:Dijkstra算法


下一篇:洛谷P1629 邮递员送信