最短路【模板】

Dijkstra算法和SPFA算法用于求最短路。(Floyd的话,还是算了吧)
最短路就是求两点之间的最短路径。
最短路径怎么求呢?
更新就是了(松弛)。
最短路【模板】_第1张图片先赋予厚望(先假设无穷大)
最短路【模板】_第2张图片然后依次更新
最短路【模板】_第3张图片
通过起点1来比较哪条路到终点20最短

最短路【模板】_第4张图片暂时选择这条绿色的路
继续比较
最短路【模板】_第5张图片
所以蓝色的路是最短的。
然后看一道纯模板题。

骑车比赛

Description

小信准备去参加骑车比赛,比赛在 n 个城市间进行,编号从 1 到 n。选手们都从城市 1 出发,终点在城市 n。

已知城市间有 m 条道路,每条道路连接两个城市,注意道路是双向的。现在小信知道了他经过每条道路需要花费的时间,他想请你帮他计算一下,他这次比赛最少需要花多少时间完成。

Input

第一行输入两个整数 n,m(1≤n≤1,000,1≤m≤5,000),分别代表城市个数和道路总数。接下来输入 m 行,每行输入三个数字 a,b,c(1≤a,b≤n,1≤c≤200),分别代表道路的起点和道路的终点,以及小信骑车通过这条道路需要花费的时间。保证输入的图是连通的。

Output

输出一行,输出一个整数,输出小信完成比赛需要的最少时间。

Sample Input 1

5 6
1 2 2
2 3 3
2 5 5
3 4 2
3 5 1
4 5 1

Sample Output 1

6


典型的最短路
Dijkstra模板:

#include
using namespace std;


int n,m;

struct node{//结构体
	int v,w;
	node(){ };
	node(int _v,int _w){
		v=_v;
		w=_w;
	}
};

vector  g[10100];

bool vis[10100];
int dst[10100];

void add(int u,int v,int w){//建图
	g[u].push_back(node(v,w));
	g[v].push_back(node(u,w));
}


void dij(int s){
	memset(dst,0x3f,sizeof dst);
	
	int u = s;
	dst[u]=0;
	vis[u]=1;
	
	int nn=n;
	while(nn--){
		for(int j=0;jdst[j]){
				mi = dst[j];
				u = j;	
			}
		}
		vis[u] = 1;	
	}
}


int main(){
	cin >> n >>m;
	int u,v,w;
	while (m--){
		cin >> u >> v >> w;
		add(u,v,w);
	}
	
	dij(1);
	cout << dst[n];
	
	return 0;
}

SPFA模板

#include
using namespace std;

const int maxn=1010;
const int inf=0x3f3f3f3f;

int n,m;

struct node{
	int v,w;
	node(){ }
	node(int _v,int _w){
		v=_v;
		w=_w;
	}
};

vector  g[maxn];
int dst[maxn];
queue  qu;
int inq[maxn];

int add(int u,int v,int w){
	g[u].push_back(node(v,w));
	g[v].push_back(node(u,w));
}

void spfa(int s){
	memset(dst,inf,sizeof dst);
	int u=s;
	dst[u]=0;
	qu.push(u);
	inq[u]=1;
	while(!qu.empty()){
		u=qu.front();
		qu.pop();
		inq[u]=0;
		for(int i=0;idst[u]+w){
				dst[v]=dst[u]+w;
				if(!inq[v]){
					qu.push(v);
					inq[v]=1;
				}
			}
		}
	}
}


int main(){
	cin >> n >> m;
	int u , v , w; 
	while (m--){
		cin >> u >> v >> w;
		add(u,v,w);
	}
	spfa(1);
	cout << dst[n]<
迷阵突围

Description

小信陷入了坐标系上的一个迷阵,迷阵上有 n个点,编号从 1 到 n。小信在编号为 1 的位置,他想到编号为 n 的位置上。小信当然想尽快到达目的地,但是他觉得最短的路径可能有风险,所以他会选择第二短的路径。现在小信知道了 n 个点的坐标,以及哪些点之间是相连的,他想知道第二短的路径长度是多少。

注意,每条路径上不能重复经过同一个点。

Input

第一行输入两个整数 n (1≤n≤200) 和 m,表示一共有 n 个点和 m 条边。

接下来输入 n 行,每行输入两个整数 xi,yi (−500≤xi,yi≤500),代表第 i 个点的坐标。

接下来输入 m 行,每行输入两个整数 pj,qj (1≤pj,qj≤n),表示点 pj 和点 qj 之间相连。

Output

输出一行,输出包含一个数,表示第二短的路径长度(小数点后面保留两位),如果第一短路径有多条,则答案就是第一最短路径的长度;如果第二最短路径不存在,则输出 -1。

Sample Input 1

3 3
1 1
2 2
3 2
1 2
2 3
1 3

Sample Output 1

2.41


模板改进。(两个dij函数)

#include
using namespace std;

int n,m;

struct node{
	int v;
	double w;
	node(){ };
	node(int _v,double _w){
		v=_v;
		w=_w;
	}
};

vector  g[10100];

bool vis[10100];
double dst[10100];

int x[10100],y[10100];
int pre[10100];
void add(int u,int v,double w){
	g[u].push_back(node(v,w));
	g[v].push_back(node(u,w));
}


void dij(int s){

	memset(vis,0,sizeof vis);
	for(int i=1;i<=n;i++){
		dst[i]=1e20;
	}
	
	int u = s;
	dst[u]=0;
	vis[u]=1;
	
	int nn=n;
	while(nn--){
		for(int j=0;jdst[u]+w){
				dst[v]=dst[u]+w;
				pre[v]=u;
			}
		}
		
		double mi=1e20;
		for(int j=1;j<=n;j++){
			if(!vis[j]&&mi>dst[j]){
				mi = dst[j];
				u = j;	
			}
		}
		vis[u] = 1;	
	}

}


void dij2(int s,int uu,int vv){
	
	memset(vis,0,sizeof vis);
	for(int i=1;i<=n;i++){
		dst[i]=1e20;
	}
	
	int u = s;
	dst[u]=0;
	vis[u]=1;
	
	int nn=n;
	while(nn--){
		for(int j=0;jdst[j]){
				mi = dst[j];
				u = j;	
			}
		}
		vis[u] = 1;	
	 
	}

}


int main(){
	cin >> n >>m;
	int u,v;
	double w;
	
	for(int i=1;i<=n;i++){
		cin >> x[i] >>y[i];
	}
	
	while (m--){
		cin >> u >> v;
		w=sqrt((x[u]-x[v])*(x[u]-x[v])+(y[u]-y[v])*(y[u]-y[v]));
		add(u,v,w);
	}
	
	dij(1);

	
	double mi=1e20;
	for(int i=n;pre[i]!=0;i=pre[i]){
		dij2(1,i,pre[i]);
		mi=min(mi,dst[n]);
	}
	     if(mi == 1e20){
	      cout << "-1"<

你可能感兴趣的:(图论)