题解 | #Rinne Loves Dynamic Graph#

Rinne Loves Dynamic Graph

https://ac.nowcoder.com/acm/problem/22600

思路

求从 1 到 n 的最短路,需注意的是 图上所有边的边权会实时改变
如何改变:每次走过一条边之后,所有的 x 都会 执行一次操作:x = 1/(1-x),x 是 边权,所有的 x 指所有边
即 边权会随着走过的边的数目的改变而改变

所以该题 不再仅仅是最短路问题,而是变成了 最短路 + dp 问题

不妨令 dist[i][j]:表示 从 1 到 i 经过了 j 条边的最短路
所以 我们最终只需求 min( dist[n][0],dist[n][1],dist[n][2],...... ,dist[n][M] ) M 代表最多走过的边的数目

但是 因为边是双向边,所以理论上来讲 我们可走过无穷条边 ,开数组的话 需开成 dist[点的数目][正无穷]
显然 开不到那么大

所以我们需要作进一步的 优化:
观察 x = 1/(1-x) ,我们不难发现 执行三次该操作之后,x 会变回最初的 x
所以我们可以把 走过的边的数目 视为 0 、1 、2
0:表示走过了 3x 条边 ,x>=0
1:表示走过了 3x + 1条边,x>=0
2:表示走过了 3x + 2条边,x>=0

现在 dist[点的数目] [正无穷] 变成了 dist[点的数目] [3]

最终只需求 min( dist[n][0], dist[n][1], dist[n][2] ) 便可

注意:因为边权随着 走过边的数目的改变 而改变,所以我们需额外让 cnt 也入队

一些变量的解释:
cnt:走过边的数目 ,cnt取值 0、1、2
dist[i][j]:表示 从 1 到 i 经过了 '' j 条边 '' 的最短路 ,j 取值 0、1、2
st[i][j] = true 表示 从 1 到 i 经过了 '' j 条边 '' 的最短路已经确定 ,j 取值 0、1、2

综上,Code 如下 .

Code

#include <bits/stdc++.h>

using namespace std;

const int N = 100010,M = 600010;

struct node{
    double distance;
    int id,cnt ;
    bool operator < (const node &x) const{
        return distance > x.distance;
    }
};
int n,m;
bool st[N][4];
double w[M],dist[N][4];
int h[N],e[M],ne[M],idx;

double change_w(double x,int t){
    t=t%3;
    while(t--){
       x = 1.0/(double)(1-x) ; 
    }
    if(x<0) x=-x;
    return x;
}

void add(int a,int b,double c){
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

double dijkstra(){
    for(int i=1;i<=n;i++) dist[i][0]=dist[i][1]=dist[i][2]=1e10;  // double型 不能用memset
    dist[1][0]=0; 
    priority_queue<node> heap;
    heap.push({0,1,0}) ;

    while(heap.size()){
        auto p=heap.top();
        heap.pop();
        int id=p.id,cnt=p.cnt;
        double distance=p.distance;

        if(st[id][cnt]) continue;

        st[id][cnt]=true;
        for(int i=h[id];i!=-1;i=ne[i]){
            int j=e[i];
            double d=change_w(w[i],cnt);
            if(dist[j][(cnt+1)%3]>distance+d){
                dist[j][(cnt+1)%3]=distance+d;
                heap.push({dist[j][(cnt+1)%3],j,(cnt+1)%3}) ;
            }
         }
    }  

    double res = 1e10;
    for(int i=0;i<3;i++) res=min(res,dist[n][i]);

    return res==1e10?-1:res;
} 

int main(){
    scanf("%d %d",&n,&m);
    memset(h,-1,sizeof h);

    while(m--){
        int a,b,w;
        scanf("%d %d %d",&a,&b,&w);
        add(a,b,w),add(b,a,w);
    }

    double t=dijkstra();
    if(t==-1) puts("-1");
    else printf("%.3f\n",t);

    return 0;
}
全部评论

相关推荐

序&nbsp;朋友们,好久不见。&nbsp;笔者在过去消失的五个月里被困在情绪牢笼中过的相当煎熬,一度丢失自己,觉得整个世界都是昏暗的。&nbsp;庆幸的是靠着自己纯硬扛也是走出来了。表达欲再度回归,所以真的很开心还有机会能在再和大家见面。&nbsp;破碎秋招&nbsp;抑郁情绪的引爆点必然是秋招期间遭受的打击了,从去年九月份腾讯转正被告知失败之后就开始疯狂投递简历,每天都在经历:简历挂、一面挂、二面挂、三面挂、HR面挂,每天睁开眼就被无所适从的挫败感包围。&nbsp;秋招的特点是即便流程走到最后一步也不一定会&nbsp;offer,因为还需要进入大池子进行横向对比,俗称泡池子,而这一泡我的大多数面试流程到后面就没了后文,这一度让我感觉非常绝望。我深知自己学历并...
SoNiC_X:我已经工作快2年了,当时高考没考好没去到想去的学校,觉得天要塌了;校招找不到工作,觉得天要塌了;现在工作觉得看不到未来,觉得天要塌了;最近最大的感悟就是:天会一直塌,但是生活也会一直继续下去,还是要调整好自己的心态,不要因为一时的困难把自己困住,要记住完蛋的日子永远在后头
点赞 评论 收藏
分享
03-11 21:46
西北大学 Java
河和静子:这只是实习工资,我学长北大通班博一的,他同学被这家天天发邮件让他去实习,一个月10w
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务