首先因为数据结构学到了邻接表 ,暑假集训又学了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;
}