zoukankan      html  css  js  c++  java
  • jzoj2702. 探险&jzoj3917. 【NOIP2014模拟11.2A组】福慧双修

    Description

    探险家小T好高兴!X国要举办一次溶洞探险比赛,获奖者将得到丰厚奖品哦!小T虽然对奖品不感兴趣,但是这个大振名声的机会当然不能错过!

    比赛即将开始,工作人员说明了这次比赛的规则:每个溶洞和其他某些溶洞有暗道相连。两个溶洞之间可能有多条道路,也有可能没有,但没有一条暗道直接从自己连到自己。参赛者需要统一从一个大溶洞出发,并再次回到这个大溶洞。

    如果就这么点限制,那么问题就太简单了,可是举办方又提出了一个条件:不能经过同一条暗道两次。这个条件让大家犯难了。这该怎么办呢?

    到了大溶洞口后,小T愉悦地发现这个地方他曾经来过,他还记得有哪些暗道,以及通过每条暗道的时间。小T现在向你求助,你能帮他算出至少要多少时间才能回到大溶洞吗?

    Input

    第一行两个数n,m表示溶洞的数量以及暗道的数量。

    接下来m行,每行4个数s、t、w、v,表示一个暗道连接的两个溶洞s、t,这条暗道正着走(s à t)的所需要的时间w,倒着走(t à s)所需要的时间v。由于溶洞的相对位置不同,w与v可能不同。

    Output

    输出一行一个数t,表示最少所需要的时间。

    Sample Input

    3 3
    1 2 2 1
    2 3 4 5
    3 1 3 2

    Sample Output

    8

    Data Constraint

    对于30%的数据,n<=500,m<=10000
    对于60%的数据,n<=2000,m<=50000
    对于100%的数据,n<=10000,m<=200000,1<=w,v<=10000

    注:3917. 【NOIP2014模拟11.2A组】福慧双修

    这题与上面的探险题意完全一样,但"福慧双修"没有重边而"探险"有重边。

    题解

    恩,我们先看到30%到60%的做法。
    然后发现就算是白痴也会打着部分分。
    直接上暴力即可。
    那么对于100%有3种做法——
    一、
    我们考虑IDA*。
    具体做法就是先在外面二分一个答案值,然后利用IDA*判断可否做。
    然后,我们可以每次以1到x号点的距离作为距离标号。
    然后剪枝即可(时间复杂度玄学)
    当然,能过,然而福慧双修的数据过大,这似乎不够保险。

    二、
    考虑DP。
    我们先在图的右边新建一个节点1’那么就从1开始走。
    我们设一个状态f[i,j]表示1第一个到i这个状态,再走到j这个距离1’的状态的最短路。
    那么就可以dp了。
    当然,这个会超空间。
    但是前者显然不用,用一个东西来标记j从哪里来即可。

    三、
    考虑重构图+dij
    你可否听过“关于spfa:他死了”吗?
    我们可以先跑一遍dij,求出dist,然后我们还要求出一个prep[i]表示从1出发到i这条最短路径中,连接1第一个出去的点。
    假设下面这张图:
    在这里插入图片描述
    那么prep就为:0,2,3,2,3,2,2

    既然我们知道了这个prep那么求来试试构建新的图。
    枚举所有的边,起点为u,终点为v,边长为z。

    • 1、当u=1,v<>1时
      • 若 prep[v]=v,即说明原点到达点 v 的最短路径即为1→v,故此时不再添加边(dist[v] 已代表该边)
      • 若 prev[v]<>v,说明原点到达点 v 的最短路径不是1→v,此时需要在新图中添加边(1,v,w)
    • 2、当u<>1,v=1时
      • 若 u<>prev[u] 说明从原点到达点 u 的最短路径中没有经过边1→u,即边u→1可以被使用,此时存在一条原点 1→prep[u]→…→u→1的路径
      • 在新图中直接创建一条 1→答案(n+1)长为dist[u]+z的边
      • 若 u=prep[u] 说明到达点 u 的最短路径是由边1→u得到,所以不能通过dist[u]+z的方式返回原点。
      • 但如果存在其他方式到达点 u,则可以通过该边返回,故在新图中创建边u→答案长为z的边。
    • 3、当u<>1,v<>1时
      • 若prep[u]<>prep[v]
      • 建1→v长为dist[u]+z的边(为什么?因为这表示可以由1→u→v→1)
      • 反之建u→v长为z的边(为什么?因为已存在在第一次dij中)

    如此看来,再建跑一次dij即可。
    但是边会有重复。那么我们可以发现,如果重复的边不是1→x,那么不会影响。
    但是1→x重复了,就有锅了。
    实际上直接在一开始时特判一下即可。
    其实如果运气好,走到顺序不同,也可以过掉。
    我就是那种运气好的。

    程序

    uses math;
    var
            bz:array[1..400000] of boolean;
            g,dist,wz,d,tov,last,next,v,prep,x,y,z1,z2:array[0..400000] of longint;
            tov1,last1,next1,v1,x1,y1,z3:array[0..400000] of longint;
            i,j,k,l,n,m,maxx,t,temp,tot,tot1,now,many:longint;
    procedure insert1(x,y,z:longint);
    begin
            inc(tot1);
            tov1[tot1]:=y;
            next1[tot1]:=last1[x];
            last1[x]:=tot1;
            v1[tot1]:=z;
    end;
    procedure insert(x,y,z:longint);
    begin
            inc(tot);
            tov[tot]:=y;
            next[tot]:=last[x];
            last[x]:=tot;
            v[tot]:=z;
    end;
    procedure up(x:longint);
    var
            temp:longint;
    begin
            while (x div 2>0) and (dist[d[x]]<dist[d[x div 2]]) do
            begin
                    wz[d[x]]:=x div 2;
                    wz[d[x div 2]]:=x;
                    temp:=d[x];
                    d[x]:=d[x div 2];
                    d[x div 2]:=temp;
                    x:=x div 2;
            end;
    end;
    procedure down(y:longint);
    var
            temp,x:longint;
    begin
            x:=1;
            while ((x*2<=t) and (dist[d[x]]>dist[d[x*2]])) or ((x*2+1<=t) and (dist[d[x]]>dist[d[x*2+1]])) do
            begin
                    if (x*2+1<=t) and (dist[d[x*2+1]]<dist[d[x*2]]) then
                    begin
                            wz[d[x]]:=x*2+1;
                            wz[d[x*2+1]]:=x;
                            temp:=d[x];
                            d[x]:=d[x*2+1];
                            d[x*2+1]:=temp;
                            x:=x*2+1;
                    end
                    else
                    begin
                            wz[d[x]]:=x*2;
                            wz[d[x*2]]:=x;
                            temp:=d[x];
                            d[x]:=d[x*2];
                            d[x*2]:=temp;
                            x:=x*2;
                    end;
            end;
    end;
    begin
            assign(input,'0data.in');reset(input);
            readln(n,m);
            for i:=1 to m do
            begin
                    readln(x[i],y[i],z1[i],z2[i]);
                    insert(x[i],y[i],z1[i]);
                    insert(y[i],x[i],z2[i]);
                    inc(many);
                    x1[many]:=x[i];
                    y1[many]:=y[i];
                    z3[many]:=z1[i];
                    inc(many);
                    x1[many]:=y[i];
                    y1[many]:=x[i];
                    z3[many]:=z2[i];
            end;
    
            fillchar(dist,sizeof(dist),127 div 3);
            maxx:=dist[1];
            t:=1;
            dist[1]:=0;
            bz[1]:=true;
            wz[1]:=t;
            d[t]:=1;
            up(t);
            while t>0 do
            begin
                    bz[d[1]]:=true;
                    i:=last[d[1]];
                    while i>0 do
                    begin
                            if (bz[tov[i]]=false) and (dist[d[1]]+v[i]<dist[tov[i]]) then
                            begin
                                    if dist[tov[i]]=maxx then
                                    begin
                                            inc(t);
                                            dist[tov[i]]:=dist[d[1]]+v[i];
                                            wz[tov[i]]:=t;
                                            d[t]:=tov[i];
                                            if d[1]=1 then
                                            begin
                                                    prep[tov[i]]:=tov[i];
                                            end
                                            else
                                            prep[tov[i]]:=prep[d[1]];
                                            up(t);
                                    end
                                    else
                                    begin
                                            dist[tov[i]]:=dist[d[1]]+v[i];
                                            prep[tov[i]]:=prep[d[1]];
                                            up(wz[tov[i]]);
                                    end;
                            end;
                            i:=next[i];
                    end;
                    wz[d[1]]:=0;
                    wz[d[t]]:=1;
                    d[1]:=d[t];
                    dec(t);
                    down(t);
            end;
    
            now:=1;
            for i:=1 to many do
            begin
                    if (x1[i]=1) and (y1[i]<>1) then
                    begin
                            if prep[y1[i]]<>y1[i] then
                            begin
                                    insert1(x1[i],y1[i],z3[i]);
                            end;
                    end
                    else
                    if (x1[i]<>1) and (y1[i]=1) then
                    begin
                            if x1[i]<>prep[x1[i]] then
                            begin
                                    insert1(1,n+1,dist[x1[i]]+z3[i]);
                            end
                            else
                            begin
                                    insert1(x1[i],n+1,z3[i]);
                            end;
                    end
                    else
                    if (x1[i]<>1) and (y1[i]<>1) then
                    begin
                            if prep[x1[i]]<>prep[y1[i]] then
                            begin
                                    insert1(1,y1[i],dist[x1[i]]+z3[i]);
                            end
                            else
                            begin
                                    insert1(x1[i],y1[i],z3[i]);
                            end;
                    end;
            end;
    
            fillchar(bz,sizeof(bz),0);
            fillchar(dist,sizeof(dist),127 div 3);
            fillchar(d,sizeof(d),0);
            t:=1;
            dist[1]:=0;
            bz[1]:=true;
            wz[1]:=t;
            d[t]:=1;
            up(t);
            while t>0 do
            begin
                    bz[d[1]]:=true;
                    i:=last1[d[1]];
                    while i>0 do
                    begin
                            if (bz[tov1[i]]=false) and (dist[d[1]]+v1[i]<dist[tov1[i]]) then
                            begin
                                    if dist[tov1[i]]=maxx then
                                    begin
                                            inc(t);
                                            dist[tov1[i]]:=dist[d[1]]+v1[i];
                                            wz[tov1[i]]:=t;
                                            d[t]:=tov1[i];
                                            up(t);
                                    end
                                    else
                                    begin
                                            dist[tov1[i]]:=dist[d[1]]+v1[i];
                                            up(wz[tov1[i]]);
                                    end;
                            end;
                            i:=next1[i];
                    end;
                    wz[d[1]]:=0;
                    wz[d[t]]:=1;
                    d[1]:=d[t];
                    dec(t);
                    down(t);
            end;
            writeln(dist[n+1]);
    end.
    
    
    
    我活在这夜里。无论周围多么黑暗,我都要努力发光!我相信着,终有一天,我会在这深邃的夜里,造就一道最美的彩虹。
  • 相关阅读:
    Java锁---偏向锁、轻量级锁、自旋锁、重量级锁
    Java自旋锁
    设计模式的原则
    CGLIB介绍与原理(通过继承的动态代理)
    Android Messenger
    Android AIDL的用法
    长连接和短连接和推送
    Java对称加密算法
    Android 热修复技术中的CLASS_ISPREVERIFIED问题
    Java类加载器
  • 原文地址:https://www.cnblogs.com/RainbowCrown/p/11148377.html
Copyright © 2011-2022 走看看