zoukankan      html  css  js  c++  java
  • 洛谷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;
    }
    
  • 相关阅读:
    oracle中查询或插入特殊字符
    html最多显示两行,css 实现两行或多行文本溢出显示省略号(...)
    RT
    发表一个自己做的WPF游戏
    用silverlight制作自己的GIS
    一个字符串切割问题
    Oracle所有者权限与调用者权限(转)
    Oracle角色权限的使用事项(转)
    Tomcat 内存溢出 详解
    forms验证:怎么验证两种身份?
  • 原文地址:https://www.cnblogs.com/KnightL/p/14584365.html
Copyright © 2011-2022 走看看