1. 程式人生 > >hdu2066 一個人的旅行(dijkstra / SPFA+鄰接表)

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