洛谷 P3371 【模板】单源最短路径(弱化版) Floyd算法 邻接矩阵/Dijkstra算法 邻接表 堆优化/Bellman-Ford算法/Bellman-Ford算法优化/SPFA算法

洛谷   P3371 【模板】单源最短路径(弱化版)   Floyd算法 邻接矩阵/Dijkstra算法 邻接表  堆优化/Bellman-Ford算法/Bellman-Ford算法优化/SPFA算法

//在线测评地址https://www.luogu.com.cn/problem/P3371

方法一:Floyd算法

 样例数据Floyd算法执行过程如下

//P3371 【模板】单源最短路径(弱化版)
//https://www.luogu.com.cn/problem/P3371
//在线测评地址https://www.luogu.com.cn/problem/P3371
//2147483647考虑采用long long
//floyd算法
//10^8*4/1024/1024=400MB数组开到10^6
//样例通过,提交,测试点2,9,10RE,1,3-8WA不敢相信。2019-11-30 13:57
/*
翻看讨论记录,
5 15 5
2 2 270
1 4 89
2 1 3
5 5 261
5 2 163
5 5 275
4 5 108
4 4 231
3 4 213
3 3 119
3 1 77
3 1 6
2 4 83
5 5 196
5 5 94
这么多从起点到终点一样的路是想干啥!!!!!
而且,从那条路能到3号点!!!!!

该题数据真毒瘤啊。看到了数据,该怎么干,那就没问题了。
两点之间有多条路径,那么选最短的。
*/
//if(a[u][v]>w)a[u][v]=w;//两点间有多条路径,选最短的。不看数据,这点根本想不到。
//提交70分,测试点1,3-8AC,2,9,10WA.还算满意。2019-11-30 14:22

#include <stdio.h>
#define LL long long
#define maxn 1010
#define INF 2147483647
LL a[maxn][maxn];
int n,m,s;
int main(){
	int k,i,j,u,v;
	LL w;
	scanf("%d%d%d",&n,&m,&s);
	for(i=1;i<=n;i++)
		for(j=1;j<=n;j++)
			if(i==j)a[i][j]=0;
			else a[i][j]=INF;
	for(i=1;i<=m;i++){
		scanf("%d%d%lld",&u,&v,&w);
		if(a[u][v]>w)a[u][v]=w;//两点间有多条路径,选最短的。不看数据,这点根本想不到。
	}
	for(k=1;k<=n;k++)
		for(i=1;i<=n;i++)
			for(j=1;j<=n;j++)
				if(a[i][j]>a[i][k]+a[k][j])
					a[i][j]=a[i][k]+a[k][j];
	printf("%lld",a[s][1]);
	for(i=2;i<=n;i++)printf(" %lld",a[s][i]);
	printf("\n");
	return 0;
}

方法二:Dijkstra算法+邻接矩阵

 

//Dijkstra+邻接矩阵
//样例通过,提交70分。2019-12-1 10:49
#include <stdio.h>
#include <string.h>
#define INF 2147483647
#define LL long long
#define maxn 1010
int n,m,s,vis[maxn];
LL a[maxn][maxn],d[maxn];
void init(){
	int i,j,u,v;
	LL w;
	scanf("%d%d%d",&n,&m,&s);
	for(i=1;i<=n;i++)
		for(j=1;j<=n;j++)
			if(i==j)a[i][j]=0;
			else a[i][j]=INF;
	for(i=1;i<=m;i++){
		scanf("%d%d%lld",&u,&v,&w);
		if(a[u][v]>w)a[u][v]=w;//取最短
	}
}
int findMin(){
	int i,k,mn=INF;
	for(i=1;i<=n;i++)
		if(!vis[i]&&mn>=d[i])
			mn=d[i],k=i;
	return k;
}
void Dijkstra(int s){
	int i,j,k;
	memset(vis,0,sizeof(vis));
	for(i=1;i<=n;i++)d[i]=INF;
	d[s]=0;
	for(j=1;j<=n;j++){//循环次数
		k=findMin(),vis[k]=1;
		for(i=1;i<=n;i++){
			if(!vis[i]&&d[i]>d[k]+a[k][i])
				d[i]=d[k]+a[k][i];
		}
	}
	printf("%lld",d[1]);
	for(i=2;i<=n;i++)printf(" %lld",d[i]);
	printf("\n");
}
int main(){
	init();
	Dijkstra(s);
	return 0;
}

方法三:Dijkstra算法+邻接表

//Dijkstra+邻接表
//样例通过,提交AC。2019-12-1 14:46真是没想到,能AC.

#include <stdio.h>
#include <string.h>
#define INF 2147483647
#define LL long long
#define maxn 10010
int n,m,s,vis[maxn],head[maxn],cnt=0;
LL d[maxn];
struct node{
	int to,next,w;
}e[500100];
void add_edge(int u,int v,LL w){//邻接表   不怕遇到重边
	cnt++,e[cnt].to=v,e[cnt].w=w,e[cnt].next=head[u],head[u]=cnt;
}
void init(){
	int i,j,u,v;
	LL w;
	memset(head,0,sizeof(head));
	scanf("%d%d%d",&n,&m,&s);
	for(i=1;i<=m;i++){
		scanf("%d%d%lld",&u,&v,&w);
		add_edge(u,v,w);
	}
}
int findMin(){
	int i,k,mn=INF;
	for(i=1;i<=n;i++)
		if(!vis[i]&&mn>=d[i])
			mn=d[i],k=i;
	return k;
}
void Dijkstra(int s){
	int i,j,k,b,u,v;
	memset(vis,0,sizeof(vis));
	for(i=1;i<=n;i++)d[i]=INF;
	d[s]=0;
	for(j=1;j<=n;j++){//循环次数
		k=findMin(),vis[k]=1;
		for(b=head[k];b;b=e[b].next){
			v=e[b].to;
			if(!vis[v]&&d[v]>d[k]+e[b].w)
				d[v]=d[k]+e[b].w;
		}
	}
	printf("%lld",d[1]);
	for(i=2;i<=n;i++)printf(" %lld",d[i]);
	printf("\n");
}
int main(){
	init();
	Dijkstra(s);
	return 0;
}

方法四:Dijkstra算法+邻接表+堆优化

//Dijkstra+邻接表+堆优化
//此文https://www.cnblogs.com/-Wind-/p/10164910.html代码写得不错,值得学习
//样例通过,提交AC。2019-12-1 21:34

#include <cstdio>
#include <cstring>
#include <queue>
#define INF 2147483647
#define LL long long
#define maxn 10010
using namespace std;
int n,m,s,vis[maxn],head[maxn],cnt=0;
LL d[maxn];
struct node{
	int w,u;//此处错写成int u,w;
	bool operator <(const node &a)const{//请注意此处格式的写法,缺一不可
		return a.w<w;
	}
};
struct node1{
	int to,next,w;
}e[500100];
priority_queue<node> q;
void add_edge(int u,int v,LL w){//邻接表   不怕遇到重边
	cnt++,e[cnt].to=v,e[cnt].w=w,e[cnt].next=head[u],head[u]=cnt;
}
void init(){
	int i,j,u,v;
	LL w;
	memset(head,0,sizeof(head));
	scanf("%d%d%d",&n,&m,&s);
	for(i=1;i<=m;i++){
		scanf("%d%d%lld",&u,&v,&w);
		add_edge(u,v,w);
	}
}
void Dijkstra(int s){
	int i,b,u,v;
	memset(vis,0,sizeof(vis));
	for(i=1;i<=n;i++)d[i]=INF;
	d[s]=0;
	q.push((node){0,s});
	while(!q.empty()){
		u=q.top().u;
		q.pop();
		if(vis[u])continue;
		vis[u]=1;
		for(b=head[u];b;b=e[b].next){
			v=e[b].to;
			if(!vis[v]&&d[v]>d[u]+e[b].w){//此处错写成if(!vis[v]&&d[v]>d[k]+e[b].w){
				d[v]=d[u]+e[b].w;//此处错写成d[v]=d[k]+e[b].w;
				q.push((node){d[v],v});
			}
		}
	}
	printf("%lld",d[1]);
	for(i=2;i<=n;i++)printf(" %lld",d[i]);
	printf("\n");
}
int main(){
	init();
	Dijkstra(s);
	return 0;
}

方法五:Bellman-Ford算法

样例通过,提交AC.2019-12-13

#include <stdio.h>
#define maxm 500010
#define INF 2147483647
#define LL long long
struct node{
	int u,v,w;
}e[maxm];
LL d[10010];
int n,m,s;
int main(){
	int i,j;
	scanf("%d%d%d",&n,&m,&s);
	for(i=1;i<=m;i++)scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
	for(i=1;i<=n;i++)d[i]=INF;
	d[s]=0;
	for(i=1;i<=n-1;i++)
		for(j=1;j<=m;j++)
			if(d[e[j].v]>d[e[j].u]+e[j].w)d[e[j].v]=d[e[j].u]+e[j].w;//以边为中转。
	printf("%lld",d[1]);
	for(i=2;i<=n;i++)printf(" %lld",d[i]);
	printf("\n");
	return 0;
}

方法六:Bellman-Ford算法优化

//Bellman-Ford优化
//样例通过,提交AC.2019-12-13

 

#include <stdio.h>
#define maxm 500010
#define INF 2147483647
#define LL long long
struct node{
	int u,v,w;
}e[maxm];//边 
LL d[10010];
int n,m,s;
int main(){
	int i,j,check;
	scanf("%d%d%d",&n,&m,&s);
	for(i=1;i<=m;i++)scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
	for(i=1;i<=n;i++)d[i]=INF;
	d[s]=0;
	for(i=1;i<=n-1;i++){
		check=0;
		for(j=1;j<=m;j++)
			if(d[e[j].v]>d[e[j].u]+e[j].w){
				d[e[j].v]=d[e[j].u]+e[j].w;//以边为中转。
				check=1;
			}	
		if(check==0)break;		
	}
	printf("%lld",d[1]);
	for(i=2;i<=n;i++)printf(" %lld",d[i]);
	printf("\n");
	return 0;
}

方法七:SPFA算法

//样例通过,提交AC.2019-12-2

#include <stdio.h>
#include <string.h>
#define INF 2147483647
#define LL long long
#define maxn 10010
int n,m,s,vis[maxn],head[maxn],cnt=0,q[maxn*10],h,t;
LL d[maxn];
struct node{
	int to,next,w;
}e[500100];
void add_edge(int u,int v,LL w){//邻接表   不怕遇到重边
	cnt++,e[cnt].to=v,e[cnt].w=w,e[cnt].next=head[u],head[u]=cnt;
}
void init(){
	int i,j,u,v;
	LL w;
	memset(head,0,sizeof(head));
	scanf("%d%d%d",&n,&m,&s);
	for(i=1;i<=m;i++){
		scanf("%d%d%lld",&u,&v,&w);
		add_edge(u,v,w);
	}
}
void SPFA(int s){
	int i,j,k,b,u,v;
	memset(vis,0,sizeof(vis));
	for(i=1;i<=n;i++)d[i]=INF;
	d[s]=0,h=t=1,q[t]=s,t++;
	while(h<t){
		u=q[h];
		for(b=head[u];b;b=e[b].next){
			v=e[b].to;
			if(d[v]>d[u]+e[b].w){
				d[v]=d[u]+e[b].w;
				if(!vis[v])q[t]=v,t++,vis[v]=1;
			}
		}
		vis[u]=0,h++;
	}
	printf("%lld",d[1]);
	for(i=2;i<=n;i++)printf(" %lld",d[i]);
	printf("\n");
}
int main(){
	init();
	SPFA(s);
	return 0;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值