行路难(SPFA+前驱记录)

与其留恋,不如洒脱。 —NEMT2018后的首题祭

行路难(SPFA+前驱记录)

题目来自洛谷P2832,难度(提高+/省选-),自以为应该是(普及/提高-)的黄题。

题目概述:给定一张有向图,在图上每进行一次移动,图的所有边权都会在原基础上+1,求算从1到N点的最小边权和,并输出这个最短路。

思路:比较显然的一件事情是,这个是个图论的最短路问题,还要记录前驱。每次移动都需要在上一次边权的基础上+1,所以我们考虑最短路的通用算法SPFA,大概这就是模板吧,再加上一个时间数组。

Q:那我和节点一样,也开一个时间队列queue< int >t可以嘛?
A:不可以的,考虑一下,如果加上这样一个队列,那就意味着你的t和q要同时进行操作,换句话说,q执行什么操作,t也得跟着操作。考虑一种比较普遍的情况,假设到达GOAL节点可以从A或者B点出发,而从A走累计距离长但我们先遍历,从B走累计距离短但我们后遍历,这样的话到达GOAL节点的时间到底算是从A还是从B呢。(好吧我表达能力差,意思大概就是这样不行,而且这样做只能得40分,就是这一段)

错误的SPFA

int spfa()
{
    int x,son,ti;
    while(!q.empty())
    {
        x=q.front(),ti=t.front();
        for(i=hd[x];i;i=a[i].nxt)
        {
            son=a[i].v;
            if(dis[son]>dis[x]+a[i].w+ti)
            {
                q.push(son);
                t.push(ti+1);
                dis[son]=dis[x]+a[i].w+ti;
                pre[son]=x;
            }
        }
        q.pop(),t.pop();
    }
}

正解

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
using namespace std;
int i,j,n,m;
int hd[10001],pre[10001],ans[10001],t[10001];
struct data
{
    int v,w,nxt;
}a[200001];

int r()
{
    int ans=0;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        ans*=10;
        ans+=ch-'0';
        ch=getchar();
    }
    return ans;
}
int xx,yy,zz,temp;

void add(int x,int y,int z)
{
    a[++temp].v=y;
    a[temp].w=z;
    a[temp].nxt=hd[x];
    hd[x]=temp;
}
queue<int>q;
int dis[10001];
int spfa()
{
    int x,son;
    while(!q.empty())
    {
        x=q.front();
        for(i=hd[x];i;i=a[i].nxt)
        {
            son=a[i].v;
            if(dis[son]>dis[x]+a[i].w+t[x])
            {
                q.push(son);
                t[son]=t[x]+1;
                dis[son]=dis[x]+a[i].w+t[x];
                pre[son]=x;
            }
        }
        q.pop();
    }
}

int main()
{
    n=r(),m=r();
    for(i=1;i<=m;i++)
    {
        xx=r(),yy=r(),zz=r();
        add(xx,yy,zz);
    }
    memset(dis,0x7f7f7f,sizeof(dis));
    dis[1]=0;
    q.push(1);
    spfa();
    cout<<dis[n]<<endl;
    j=n;
    int tot=0;
    while(j!=1)
    {
        ans[++tot]=j;
        j=pre[j];
    }
    cout<<1;
    for(i=tot;i>=1;i--)
    {
        cout<<" "<<ans[i];
    }
    return 0;
}
/*
5 7
1 5 7
1 2 1
1 4 1
3 5 1
2 3 1
2 4 1
4 5 1
*/

上图,传统不能丢。

今天是可爱的埃罗芒阿老师(划掉)和泉纱雾哦
这里写图片描述

猜你喜欢

转载自blog.csdn.net/Stockholm_Sun/article/details/81326462