hdu2066 一個人的旅行(dijkstra / SPFA+鄰接表)
阿新 • • 發佈:2018-12-23
首先因為資料結構學到了鄰接表 ,暑假集訓又學了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; }