洛谷 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;
}