Luogu 题解 P5468 【[NOI2019]回家路线】

题目

当时打同步赛时用的暴力dfs,才95分,WA掉1个点。后来想了想,这题可以用SPFA最短路过。

\(dis[x][y]\)表示在\(x\)时间,从\(1\)站点到\(y\)站点的最小烦躁值,就可以用SPFA来做啦~

具体分析看代码:


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
int n,m,aa,bb,cc;
int anss=999999999;
struct T{
    int u;
    int v;
    int st;
    int ed;//st是开始时间,ed是到达时间
    bool operator <(const T& a) const {
        return u<a.u;
    }//暴力时用的,懒得删掉。
}tr[200010];
int nxt[200010],fst[100010];
bool bo[1001][100001];//标记时间x,站点y有没有到达过。
int dis[1001][100001];//
queue<int>q;//spfa队列,存点
queue<int>tim;//存时间
inline int hs(int x){
    return aa*x*x+bb*x+cc;
}//算烦躁值
int main() {
    memset(dis,0x7f,sizeof(dis));
    scanf("%d%d%d%d%d",&n,&m,&aa,&bb,&cc);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d%d",&tr[i].u,&tr[i].v,&tr[i].st,&tr[i].ed);
        nxt[i]=fst[tr[i].u];
        fst[tr[i].u]=i;//邻接表存图
    }
    q.push(1);
    tim.push(0);
    bo[0][1]=1;
    dis[0][1]=0;//初始化
    while(!q.empty()){
        int x=q.front();
        int ti=tim.front();
        q.pop();
        tim.pop();
        bo[ti][x]=0;
        for(int k=fst[x];k;k=nxt[k]){
            if(tr[k].st<ti) continue;
            if(tr[k].v==n){//判断一下,如果到达n站点还要加上当前时间
                if(dis[tr[k].ed][tr[k].v]>dis[ti][x]+hs(tr[k].st-ti)+tr[k].ed){
                    dis[tr[k].ed][tr[k].v]=dis[ti][x]+hs(tr[k].st-ti)+tr[k].ed;
                    if(!bo[tr[k].ed][tr[k].v]){
                        bo[tr[k].ed][tr[k].v]=1;
                        q.push(tr[k].v);
                        tim.push(tr[k].ed);
                    }
                } 
            }
            else {
                if(dis[tr[k].ed][tr[k].v]>dis[ti][x]+hs(tr[k].st-ti)){//如果在当前火车到达的时间到tr[k].v站点的最小烦躁值大于当前站点的烦躁值,就可以松弛。
                    dis[tr[k].ed][tr[k].v]=dis[ti][x]+hs(tr[k].st-ti);
                    if(!bo[tr[k].ed][tr[k].v]){
                        bo[tr[k].ed][tr[k].v]=1;
                        q.push(tr[k].v);
                        tim.push(tr[k].ed);
                    }
                }   
            }
        }
    }
    anss=999999999;
    for(int k=1;k<=m;k++){
        if(tr[k].v==n){
            anss=min(anss,dis[tr[k].ed][n]);
        }//判断一下,因为可能有很多个时刻都可以到达终点,需要取最小值。
    }
    cout<<anss;//输出
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Jrzy/p/12232628.html