hdu2066 一个人的旅行(dijkstra / SPFA+邻接表)

 

首先因为数据结构学到了邻接表 ,暑假集训又学了SPFA,最近又在复习图的题,想着做一下SPFA+邻接表的题就找了这道题。。
所以本博客的实质就是记录学习的SPFA和邻接表
但好像我写的是SPFA+链式前向星存图

SPFA用队列实现 最主要的一点就是可以判负环(当然这道题没有用),然后我理解了好久的地方就是为什么标记过得结点,从队列拿出来松弛后又释放该结点,即结点的重复使用。 现在终于明白可以把它看成和dijkstra的不同。

dijkstra每次都找离源点最近的点进行松弛操作,即有一个排序对边的权值,这样就只用标记你用过的结点就可以了,用这个结点去松弛与他相邻的点,重复至最后,即最短路;而SPFA每次对结点进行松弛时,所有的点都可能是他的中间点来进行松弛,没有大小顺序关系,所以每次用某点,若能松弛就标记,入队列,但下次拿他松弛别的点时,再释放它。

至于前向星存图,我看的是 啊哈磊 的数组模拟实现邻接表学会的https://blog.csdn.net/ahalei/article/details/23356781

SPFA+前向星:

#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<stdlib.h>
#include<queue>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=10005;
struct node{
	int v;
	int w;
	int next;
}e[maxn];
int head[maxn];
int len=0;
int dis[maxn];
int vis[maxn];
int a[maxn];
int b[maxn];
void adde(int u,int v,int w){
	e[len].v=v;
	e[len].w=w;
	e[len].next=head[u];
	head[u]=len++;
}
void spfa(int s){
    //初始化 
	for(int i=0;i<maxn;i++)
	    dis[i]=inf;
	    
	dis[s]=0;
	vis[s]=1;
	queue<int>q;
	q.push(s);
	while(!q.empty()){	
		int u=q.front();
		q.pop();
		vis[u]=0;//释放该结点 
		for(int i=head[u];i!=-1;i=e[i].next){
			  int v=e[i].v;
			if(dis[v]>dis[u]+e[i].w){
				dis[v]=dis[u]+e[i].w;
				if(vis[v]==0){//如果没有用过该点则入队列  用该点去松弛其他点 
					vis[v]=1;//标记该点后队列有他就不入队了 即 前面已经有其他结点松弛过该点该点已在队列中 
				    q.push(v);
				}				   
			}
		}		
	} 
}
int main(){
	int t,s,d;
	while(cin>>t>>s>>d){
		memset(head,-1,sizeof(head));
	    memset(vis,0,sizeof(vis));
		for(int i=0;i<t;i++){
			int x,y,z;
			cin>>x>>y>>z;//无向图 
			adde(x,y,z);
			adde(y,x,z);
		}		  
		int t=inf;
		for(int i=0;i<s;i++)
		  cin>>a[i];
		for(int i=0;i<d;i++)
		  cin>>b[i];		    
		for(int i=0;i<s;i++){
			len=0;
			spfa(a[i]);
			for(int i=0;i<d;i++){
				if(dis[b[i]]<t){
					t=dis[b[i]];
				}
			}	
		}
		cout<<t<<endl;
	}
	return 0;
}

dij方法 即可以把             草儿的家看做0点,然后去找从0点到最远点的最短路,就是个普通的dij;

#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<stdlib.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1005;
int t,s,d;
int dis[maxn];
int vis[maxn];
int e[maxn][maxn];
int N;
int b[maxn];
void dij(int s){
	
	 for(int i=0;i<=N;i++){
	 	dis[i]=e[s][i];
	 	vis[i]=0;
	 }
	 dis[s]=0;
	 vis[s]=1;
	 
	for(int i=0;i<N;i++){
		int minn=inf,u;
		for(int j=0;j<=N;j++){
			if(!vis[j]&&dis[j]<minn){
				minn=dis[j];
				u=j;
			}
		}
		vis[u]=1;
		for(int v=0;v<=N;v++){
			if(dis[v]>dis[u]+e[u][v]&&!vis[v])
			  dis[v]=dis[u]+e[u][v];
		}
	}	
}
int main(){
	while(cin>>t>>s>>d){
		N=0;
		//初始化 
		for(int i=0;i<maxn;i++)
		   for(int j=0;j<maxn;j++){
		   	if(i==j)
		   	  e[i][j]=0;
		   	else
			  e[i][j]=inf;     
		   }
		while(t--){
			int x,y,z;
			cin>>x>>y>>z;
			N=max(N,max(x,y));
			if(e[x][y]>z)
			e[x][y]=z;
			if(e[y][x]>z)
			e[y][x]=z;
		} 
		for(int i=0;i<s;i++){
			int t;
			cin>>t;
			e[0][t]=0;
			e[t][0]=0;
		}
		for(int i=0;i<d;i++){
			cin>>b[i];
		}
		dij(0);	
		int mn=inf;
		for(int i=0;i<d;i++){
			if(mn>dis[b[i]]){
				mn=dis[b[i]];
			}
		}
		cout<<mn<<endl;
	}
	return 0;
}  

 

    原文作者:Dijkstra算法
    原文地址: https://blog.csdn.net/gml1999/article/details/83903533
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞