早晨碰到了一题挺裸的最短路问题需要打印路径:vijos1635
1.首先说说spfa的方法:
其实自己之前打的最多的spfa是在网格上的那种,也就是二维的
一维的需要邻接表+queue
以及对于queue的操作,自己也是醉了
这里贴一个模板(不含打印路径):
#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
using namespace std;
const int maxn=10100;
int n,m,k,t,x,y,s,ans=0;
long long tot=0;
struct edge{
int from,to,w,next;
}e[10100000];
int head[maxn],dist[maxn];
bool vis[maxn];
void add(int x,int y,int z){//邻接表
e[tot].from=x;
e[tot].to=y;
e[tot].w=z;
e[tot].next=head[x];
head[x]=tot++;
}
void spfa(int s){
queue<int>q;
memset(dist,63,sizeof(dist));
memset(vis,false,sizeof(vis));//感觉这里的赋值和二维的略有区别,这里是初始值false
q.push(s);
dist[s]=0;
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=false;②
for(int i=head[u];i!=-1;i=e[i].next){
int v=e[i].to;
if(dist[v]>dist[u]+e[i].w){
dist[v]=dist[u]+e[i].w;
if(!vis[v]){ //如果已经入队,或是初始值①
vis[v]=true;
q.push(v);
}
}
}
}
}
int main(){
scanf("%d",&n);
memset(head,-1,sizeof(head));//记得head赋值为-1
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
scanf("%d",&s);
if(s!=0){
add(i,j,s);
}
}
spfa(1);
printf("%d",dist[n]);
return 0;
}
好好感受一下①和②
对于spfa打印路径问题:
这里就需要用上指针的思想,去找n的前驱
所以如果dist有更新值,那么就记录下,但是这里要理解,
你记录的并不是根据这条路的路径顺序记的
说白了就是,f[1]并不是第一条路径
而是让v->u,这才是f应该做的
if(dist[v]>dist[u]+e[i].w){
dist[v]=dist[u]+e[i].w;
f[v]=u;//在更新值的后面加上这个
if(!vis[v]){
vis[v]=true;
q.push(v);
}
}
以及调用一个递归函数寻找前驱:
void printpath(int k){
if(k!=0){
printpath(f[k]);
printf("%d ",k);
}
}
2.FLOYD算法:
初始化 f[i][j]=j;
之后也是在更新值后面加上一条语句:
k=1-n
i=1-n
j=1-n
if(..>..)
dist[i][j]=dist[i][k]+dist[k][j];
f[i][j]=f[i][k];
比如要打印v,w的路径:
k=P[v][w]; /* 获得第一个路径顶点下标 */
printf(" path: %d",v); /* 打印源点 */
while(k!=w) /* 如果路径顶点下标不是终点 */
{
printf(" -> %d",k); /* 打印路径顶点 */
k=P[k][w]; /* 获得下一个路径顶点下标 */
}
printf(" -> %d\n",w); /* 打印终点 */