图论 || 最短路径(dij vs spfa)

F - Til the Cows Come Home

Bessie is out in the field and wants to get back to the barn to get as much sleep as possible before Farmer John wakes her for the morning milking. Bessie needs her beauty sleep, so she wants to get back as quickly as possible. 

Farmer John's field has N (2 <= N <= 1000) landmarks in it, uniquely numbered 1..N. Landmark 1 is the barn; the apple tree grove in which Bessie stands all day is landmark N. Cows travel in the field using T (1 <= T <= 2000) bidirectional cow-trails of various lengths between the landmarks. Bessie is not confident of her navigation ability, so she always stays on a trail from its start to its end once she starts it. 

Given the trails between the landmarks, determine the minimum distance Bessie must walk to get back to the barn. It is guaranteed that some such route exists.

Input

* Line 1: Two integers: T and N 

* Lines 2..T+1: Each line describes a trail as three space-separated integers. The first two integers are the landmarks between which the trail travels. The third integer is the length of the trail, range 1..100.

Output

* Line 1: A single integer, the minimum distance that Bessie must travel to get from landmark N to landmark 1.

Sample Input

5 5
1 2 20
2 3 30
3 4 20
4 5 20
1 5 100

Sample Output

90

给出t条路径和n个点,求从点n到点1的最短路径

 

 

 

 

Dijkstra算法(堆优化)

找到最短距离(d[i]表示起点s到点i的距离,最短距离即d[i]最小)已经确定的点(第一个是起点),从它出发更新与它相连的点的最短距离

(如果用二维数组存图要去重边,用链式向前星存法可以不用考虑这个问题)

 

 

spfa(SLF优化)

SLF:small label first,使用双向队列deque,如果dis[i]<dis[q.front()],那么将i点插入队首(先更新),否则插入队尾

从起点开始,对每个点进行松弛操作,更新dis,最后得到最短路径

稳定性比较差,可以用dij还是用dij

 

如果这道题中有负权边,因为是无向图,也就是说有负环,以上两种做法都解不了,但spfa可以判断有没有负环(当一个点重复进入队列n次( >n-1 )以上,就存在负环

 

关于有向图中带负权边的问题

用spfa可以解决这个问题啦

然后发现如果把dij中if(q.front()==t)break(如果终点t最短距离已经确定,则退出),发现也可以搞定,但是显然按照dij的原理是不可能能处理负权边的,因为dij是从最短距离已经确定的点出发,这是前提,如果存在负权边,那么后续操作会使最短路径变小,破坏了前提

想了很久,发现去掉以上所说的话,其实堆优化的dij就相当于SLF优化的spfa了,只是队列用法不同而已

 

 

#include<stdio.h>
#include<vector>
#include<algorithm>
#include<string.h>
#include<iostream>
#include<fstream>
#include<math.h>
#include<stack>
#include<queue>
#include<bitset>
#include<utility>
#include<set>
#include<map>
#include<sstream>
#define INF 0x7f7f7f7f
using namespace std;
typedef long long ll;
const double eps=0.0000000000001;
const ll mod=1e18;
const int N=10005;
int t;
int n;
struct P{
	int v;
	int dis;
	bool friend operator<(P a,P b){
		return a.dis>b.dis;
	}
};
struct Edge{
	int y;
	int nt;
	int dis;
};
int head[N];
Edge e[N<<1];
int dis[N];
void add(int i,int x,int y,int w){
	e[i].y=y;
	e[i].dis=w;
	e[i].nt=head[x];
	head[x]=i;
}
void dij(){
	memset(dis,127,sizeof(dis));
	priority_queue<P> q;
	P s;
	s.v=n;
	s.dis=0;
	dis[n]=0;
	q.push(s);
	while(!q.empty()){
		P x=q.top();
		q.pop();
		if(x.v==1)return;
		for(int i=head[x.v];i!=-1;i=e[i].nt){
			if(dis[x.v]+e[i].dis<dis[e[i].y]){
				dis[e[i].y]=dis[x.v]+e[i].dis;
				P a;
				a.v=e[i].y;
				a.dis=dis[a.v];
				q.push(a);
			}
		}
	}
}
int main(){	
	scanf("%d%d",&t,&n);
	int x,y,w;
	int k=0;
	memset(head,-1,sizeof(head));
	for(int i=0;i<t;i++){
		scanf("%d%d%d",&x,&y,&w);
		add(k,x,y,w);
		k++;
		add(k,y,x,w);
		k++;
	}
	dij();
	printf("%d\n",dis[1]);
	return 0;
}

 

#include<stdio.h>
#include<vector>
#include<algorithm>
#include<string.h>
#include<iostream>
#include<fstream>
#include<math.h>
#include<stack>
#include<queue>
#include<bitset>
#include<utility>
#include<set>
#include<map>
#include<sstream>
#define INF 0x7f7f7f7f
using namespace std;
typedef long long ll;
const double eps=0.0000000000001;
const ll mod=1e18;
const int N=10005;
int t;
int n;
struct Edge{
	int y;
	int nt;
	int dis;
};
int head[N];
Edge e[N<<1];
bool f[N];
int dis[N];
void add(int i,int x,int y,int w){
	e[i].y=y;
	e[i].dis=w;
	e[i].nt=head[x];
	head[x]=i;
}
int spfa(int s,int t){
	memset(dis,127,sizeof(dis));
	memset(f,0,sizeof(f));
	deque<int> q;
	dis[s]=0;
	f[s]=1;
	q.push_back(s);
	while(!q.empty()){
		int x=q.front();
		q.pop_front();
		f[x]=0;
		for(int i=head[x];i!=-1;i=e[i].nt){
			if(dis[x]+e[i].dis<dis[e[i].y]){
				dis[e[i].y]=dis[x]+e[i].dis;
				if(f[e[i].y]==0&&!q.empty()&&dis[e[i].y]<dis[q.front()]){
					q.push_front(e[i].y);	
				}
				else q.push_back(e[i].y);
				f[e[i].y]=1;
			}
			
		}
	}
}
int main(){	
	scanf("%d%d",&t,&n);
	int x,y,w;
	int k=0;
	memset(head,-1,sizeof(head));
	for(int i=0;i<t;i++){
		scanf("%d%d%d",&x,&y,&w);
		add(k,x,y,w);
		k++;
		add(k,y,x,w);
		k++;
	}
	spfa(n,1);
	printf("%d\n",dis[1]);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bekote

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值