Loading

洛谷P1266

Description

给定一张有向图,对于图中的每条边,给出它的长度以及经过它时的速度,当某条边给定的速度为 \(0\) 时,它的速度可以是任意一条连向这条边的起点的边的速度。

求从 \(0\) 号点出发,到达 \(D\) 号所用时间最少的一条路径。

Solution

根据题目信息,大概可以猜想到这是求一个最短路(或者在这个题目中叫做最快路)。

但是题目中只给出了路程与速度,并未给出时间,就要考虑该怎么转化。

显然,根据公式 \(\large{t=\frac{s}{v}}\),我们便可以将路程与速度转化成时间,然后将它作为边权跑一个最短路。

但是这里还有第二个问题,那就是某些边的速度不确定,也就是它的时间(边权)不确定,所以我们要通过某些方法确定它的速度。

如果直接贪心地钦定某条无速度的边是当前能连到它的最快速度,可能会出现这条路并不是最短路的情况。

所以这个速度并不能提前确定,而是在我们遍历的时候择优确定。

我们知道,在最短路中,\(dis_i\) 一般表示从起点到 \(i\) 号点的最短距离。

为了比较各个速度下的最短距离,我们可以在原基础上增加一维,也就是设 \(dis_{i,j}\) 表示从起点到第 \(i\) 号点,且在第 \(i\) 号点时速度为 \(j\) 的最短距离。

这样进行最短路更新时可以更新各个速度下的最短路,也就可以找出最快的路径了。

关于代码的实现

  • 我们可以开一个结构体,存储每个点以及这个点开始的速度是多少,用于求最短路时的更新。

  • 输出方案时,可以按最短路统计路径的方法,记录路径上每个点的前驱节点,然后递归输出即可。

  • 注意点是从 \(0\)\(n-1\) 编号的。

Code

#include<queue>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define maxn 2100
#define maxm 100100
#define INF 0x3f3f3f3f
//#define int long long

using namespace std;

int n,m,end,tot;
double Dis[maxn][maxn];
int vis[maxn][maxn],head[maxn];
struct node{int pos,vold;}pre[maxn][maxn];
struct edge{int to,v,len,nxt;}e[maxm];

int read(){
	int s=0,w=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
	return s*w;
}

void add(int fr,int to,int v,int len){
    e[++tot].to=to;e[tot].len=len;
    e[tot].v=v;e[tot].nxt=head[fr];
    head[fr]=tot;
}

void spfa(){
    memset(pre,-1,sizeof pre);
    memset(Dis,127,sizeof Dis);
    Dis[1][70]=0;vis[1][70]=1;
    queue<node> d;d.push((node){1,70});
    while(!d.empty()){
        int u=d.front().pos;
        int v=d.front().vold;
        d.pop();vis[u][v]=0;
        for(int i=head[u];i;i=e[i].nxt){
            int to=e[i].to,vold=e[i].v;
            if(vold==0) vold=v;
            if(Dis[to][vold]>Dis[u][v]+(double)(e[i].len/(vold/1.0))){
                Dis[to][vold]=Dis[u][v]+(double)(e[i].len/(vold/1.0));
                pre[to][vold].pos=u;pre[to][vold].vold=v;
                if(!vis[to][vold]){
                    vis[to][vold]=1;
                    d.push((node){to,vold});
                }
            }
        }
    }
}

void print(int pos,int vold){
    if(pre[pos][vold].pos!=-1) 
        print(pre[pos][vold].pos,pre[pos][vold].vold);
    printf("%d ",pos-1);
}

int main(){
    n=read();m=read();end=read()+1;
    for(int i=1,fr,to,vold,len;i<=m;i++){
        fr=read()+1;to=read()+1;
        vold=read();len=read();
        add(fr,to,vold,len);
    }
    spfa();double minx=INF*1.0,id;
    for(int i=1;i<=500;i++)
        if(minx>Dis[end][i])
            minx=Dis[end][i],id=i;
    print(end,id);
    return 0;
}
posted @ 2021-03-26 21:45  KnightL  阅读(39)  评论(0编辑  收藏  举报