zoukankan      html  css  js  c++  java
  • HDU-6290 奢侈的旅行 (Dijkstra+堆优化)

    高玩小Q不仅喜欢玩寻宝游戏,还喜欢一款升级养成类游戏。在这个游戏的世界地图中一共有nn个城镇,编号依次为11到nn。

    这些城镇之间有mm条单向道路,第ii 条单项道路包含四个参数ui,vi,ai,biui,vi,ai,bi,表示一条从uiui号城镇出发,在vivi号城镇结束的单向道路,因为是单向道路,这不意味着小Q可以从vivi沿着该道路走到uiui。小Q的初始等级levellevel为11,每当试图经过一条道路时,需要支付cost=log2level+ailevelcost=log2⁡level+ailevel点积分,并且经过该道路后,小Q的等级会提升aiai级,到达level+ailevel+ai级。但是每条道路都会在一定意义上歧视低消费玩家,准确地说,如果该次所需积分cost<bicost<bi,那么小Q不能经过该次道路,也不能提升相应的等级。

    注意:本游戏中等级为正整数,但是积分可以是任意实数。

    小Q位于11号城镇,等级为11,现在为了做任务要到nn号城镇去。这将会是一次奢侈的旅行,请写一个程序帮助小Q找到需要支付的总积分最少的一条路线,或判断这是不可能的。

    Input第一行包含一个正整数T(1T30)T(1≤T≤30),表示测试数据的组数。

    每组数据第一行包含两个整数n,m(2n100000,1m200000)n,m(2≤n≤100000,1≤m≤200000),表示城镇数和道路数。

    接下来mm行,每行四个整数ui,vi,ai,bi(1ui,vin,uivi,0ai109,0bi60)ui,vi,ai,bi(1≤ui,vi≤n,ui≠vi,0≤ai≤109,0≤bi≤60),分别表示每条单向道路。
    Output对于每组数据,输出一行一个整数,即最少所需的总积分的整数部分,如:4.99994.9999输出44,1.01.0输出11。若不存在合法路线请输出1−1。Sample Input

    1
    3 3
    1 2 3 2
    2 3 1 6
    1 3 5 0

    Sample Output

    2


    题意:

    给你n个点,m条边,每条边有u,v,a,b这四个值,初始等级为1.问你从1点到n点需要花费的最小积分

    题解:

    每次走过一条路i 的消费是 log2(( level i +ai)/(level i) )  式子可以转化为log2( ai  +  level i) - log2( level i),所以每次的消费就是log2( ai  +  level i) - log2( level i),如果走两条路,从1到v1再到v2 :那么消费就是
     log2(a1+ level1) - log2( level 1)+log2(a2+ level2)-log2(level2), 因为level2就是level1+a1,所以可以化简为- log2( level 1)+log2(a2+ level2),如果把这个式子扩长,可以发现中间的部分都可以通过一加一减化掉,只剩下-log2(1)+log2(level n) 因为log2(1)==0 所以只要求得到n时的最小等级leveln,对其求log2(level n)就是结果最小等级就可以直接用Dijkstra求最短路求得

    思路参考链接:https://blog.csdn.net/chimchim04/java/article/details/90068314
     
     

    我的出错点1:

    #include<stdio.h>
    #include<string.h>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #include<math.h>
    using namespace std;
    const int INF=0x3f3f3f3f;
    const int maxn=2e5+5;
    typedef long long ll;
    const ll MAX=1e17;
    const ll inf=(ll)1<<61;
    struct shudui1
    {
        ll start,value;
        bool operator < (const shudui1 q)const
        {
            return value>q.value; //最短路模板中这里应该是大于号,我写成了小于号
        }
    } str1;

    下面代码就是这个原因错的:

      1 #include<stdio.h>
      2 #include<string.h>
      3 #include<iostream>
      4 #include<algorithm>
      5 #include<queue>
      6 #include<vector>
      7 #include<math.h>
      8 using namespace std;
      9 const int INF=0x3f3f3f3f;
     10 const int maxn=2e5+5;
     11 typedef long long ll;
     12 const ll MAX=1e17;
     13 const ll inf=(ll)1<<61;
     14 struct shudui1
     15 {
     16     ll start,value;
     17     bool operator < (const shudui1 q)const
     18     {
     19         return value<q.value;
     20     }
     21 } str1;
     22 struct node
     23 {
     24     ll a,v,nex,b;
     25 } e[maxn];
     26 ll tot,v[maxn],p[70],vis[maxn],head[maxn];
     27 void add(ll u,ll v,ll a,ll b)
     28 {
     29     e[tot].v=v,e[tot].a=a,e[tot].b=b;
     30     e[tot].nex=head[u];
     31     head[u]=tot++;
     32     //printf("%d %d
    ",tot-1,v);
     33 }
     34 priority_queue<shudui1>r; //里面的数据默认是从小到大排序,这样就不用通过for循环遍历在每一次找v里面的最小值,可以直接找到最小值,减少代码运行次数
     35 void JK(ll s)
     36 {
     37     v[s]=1;
     38     str1.start=s;
     39     str1.value=1;
     40     r.push(str1);
     41     while(!r.empty())
     42     {
     43 
     44         ll x,y;
     45         str1=r.top();
     46         r.pop();
     47         x=str1.start;
     48         y=str1.value;
     49         //printf("%lld***
    ",x);
     50         if(vis[x]) continue;
     51         vis[x]=1;
     52         //printf("**%lld
    ",len);
     53         for(ll i=head[x]; i!=-1; i=e[i].nex)
     54         {
     55 
     56             ll vv=e[i].v,a=e[i].a,b=e[i].b;
     57             ll temp=1+a/v[x];
     58             //printf("%lld %lld
    ",temp,p[b]);
     59             if(temp<p[b]) continue;
     60             //printf("%lld %lld
    ",v[x]+v,v[vv]);
     61             if((v[x]+a<v[vv]))
     62             {
     63                 //printf("**");
     64                 v[vv]=v[x]+a;
     65                 str1.start=vv;
     66                 str1.value=v[vv];
     67                 r.push(str1);
     68             }
     69         }
     70     }
     71 }
     72 int main()
     73 {
     74 //    double xx=1.99;
     75 //    printf("%.0lf
    ",xx);
     76     ll t;
     77     p[0]=1;
     78     for(ll i=1; i<=60; ++i)
     79         p[i]=(ll)p[i-1]*(ll)2;
     80     scanf("%lld",&t);
     81     while(t--)
     82     {
     83         memset(head,-1,sizeof(head));
     84         tot=0;
     85         ll n,m;
     86         scanf("%lld%lld",&n,&m);
     87         for(ll i=1; i<=n; ++i)
     88             v[i]=inf,vis[i]=0;
     89         while(m--)
     90         {
     91             ll x,y,z1,z2;
     92             scanf("%lld%lld%lld%lld",&x,&y,&z1,&z2);
     93             add(x,y,z1,z2);
     94         }
     95         JK(1);
     96         if(v[n]>=inf) printf("-1
    ");
     97         else
     98         {
     99             double x=log2(v[n]);
    100             printf("%lld
    ",(ll)x);
    101         }
    102     }
    103     return 0;
    104 }
    View Code

    出错点2:

    while(!r.empty())
        {
    
            ll x,y;
            str1=r.top();
            r.pop();
            x=str1.start;
            y=str1.value;
            //printf("%lld***
    ",x);
            if(vis[x]) continue;
            vis[x]=1;
            //printf("**%lld
    ",len);
            for(ll i=head[x]; i!=-1; i=e[i].nex)
            {
    
                ll vv=e[i].v,a=e[i].a,b=e[i].b;
                ll temp=1+a/v[x];  //最短路算法里面这里应该是除于v[x],我却写成了str1.value
                //printf("%lld %lld
    ",temp,p[b]);
                if(temp<p[b]) continue;
                //printf("%lld %lld
    ",v[x]+v,v[vv]);
                if((v[x]+a<v[vv]))
                {
                    //printf("**");
                    v[vv]=v[x]+a;
                    str1.start=vv;
                    str1.value=v[vv];
                    r.push(str1);
                }
            }
        }

    原代码:

      1 #include<stdio.h>
      2 #include<string.h>
      3 #include<iostream>
      4 #include<algorithm>
      5 #include<queue>
      6 #include<vector>
      7 #include<math.h>
      8 using namespace std;
      9 const int INF=0x3f3f3f3f;
     10 const int maxn=2e5+5;
     11 typedef long long ll;
     12 const ll MAX=1e17;
     13 const ll inf=(ll)1<<61;
     14 struct shudui1
     15 {
     16     ll start,value;
     17     bool operator < (const shudui1 q)const
     18     {
     19         return value>q.value;  //这里是大于号
     20     }
     21 } str1;
     22 struct node
     23 {
     24     ll a,v,nex,b;
     25 } e[maxn];
     26 ll tot,v[maxn],p[70],vis[maxn],head[maxn];
     27 void add(ll u,ll v,ll a,ll b)
     28 {
     29     e[tot].v=v,e[tot].a=a,e[tot].b=b;
     30     e[tot].nex=head[u];
     31     head[u]=tot++;
     32     //printf("%d %d
    ",tot-1,v);
     33 }
     34 priority_queue<shudui1>r; //里面的数据默认是从小到大排序,这样就不用通过for循环遍历在每一次找v里面的最小值,可以直接找到最小值,减少代码运行次数
     35 void JK(ll s)
     36 {
     37     v[s]=1;
     38     str1.start=s;
     39     str1.value=1;
     40     r.push(str1);
     41     while(!r.empty())
     42     {
     43 
     44         ll x,y;
     45         str1=r.top();
     46         r.pop();
     47         x=str1.start;
     48         y=str1.value;
     49         //printf("%lld***
    ",x);
     50         if(vis[x]) continue;
     51         vis[x]=1;
     52         //printf("**%lld
    ",len);
     53         for(ll i=head[x]; i!=-1; i=e[i].nex)
     54         {
     55 
     56             ll vv=e[i].v,a=e[i].a,b=e[i].b;
     57             ll temp=1+a/v[x];//最短路算法里面这里应该是除于v[x],我却写成了str1.value
     58             //printf("%lld %lld
    ",temp,p[b]);
     59             if(temp<p[b]) continue;
     60             //printf("%lld %lld
    ",v[x]+v,v[vv]);
     61             if((v[x]+a<v[vv]))
     62             {
     63                 //printf("**");
     64                 v[vv]=v[x]+a;
     65                 str1.start=vv;
     66                 str1.value=v[vv];
     67                 r.push(str1);
     68             }
     69         }
     70     }
     71 }
     72 int main()
     73 {
     74 //    double xx=1.99;
     75 //    printf("%.0lf
    ",xx);
     76     ll t;
     77     p[0]=1;
     78     for(ll i=1; i<=60; ++i)
     79         p[i]=(ll)p[i-1]*(ll)2;
     80     scanf("%lld",&t);
     81     while(t--)
     82     {
     83         memset(head,-1,sizeof(head));
     84         tot=0;
     85         ll n,m;
     86         scanf("%lld%lld",&n,&m);
     87         for(ll i=1; i<=n; ++i)
     88             v[i]=inf,vis[i]=0;
     89         while(m--)
     90         {
     91             ll x,y,z1,z2;
     92             scanf("%lld%lld%lld%lld",&x,&y,&z1,&z2);
     93             add(x,y,z1,z2);
     94         }
     95         JK(1);
     96         if(v[n]>=inf) printf("-1
    ");
     97         else
     98         {
     99             double x=log2(v[n]);
    100             printf("%lld
    ",(ll)x);
    101         }
    102     }
    103     return 0;
    104 }
    View Code

    整理之后的代码:

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<iostream>
     4 #include<algorithm>
     5 #include<queue>
     6 #include<vector>
     7 #include<math.h>
     8 using namespace std;
     9 const int INF=0x3f3f3f3f;
    10 const int maxn=2e5+5;
    11 typedef long long ll;
    12 const ll MAX=1e17;
    13 const ll inf=(ll)1<<61;
    14 struct shudui1
    15 {
    16     ll v,c;
    17     shudui1(ll x=0,ll y=0):v(x),c(y) {}
    18     bool operator < (const shudui1 q)const
    19     {
    20         return c>q.c;
    21     }
    22 } str1;
    23 struct node
    24 {
    25     ll a,v,nex,b;
    26 } e[maxn];
    27 ll tot,dis[maxn],p[70],vis[maxn],head[maxn];
    28 void add(ll u,ll v,ll a,ll b)
    29 {
    30     e[tot].v=v,e[tot].a=a,e[tot].b=b;
    31     e[tot].nex=head[u];
    32     head[u]=tot++;
    33     //printf("%d %d
    ",tot-1,v);
    34 }
    35 priority_queue<shudui1>r; //里面的数据默认是从小到大排序,这样就不用通过for循环遍历在每一次找v里面的最小值,可以直接找到最小值,减少代码运行次数
    36 void JK(ll s,ll n)
    37 {
    38 
    39     dis[s]=1;
    40     str1.v=s;
    41     str1.c=1;
    42     r.push(str1);
    43     while(!r.empty())
    44     {
    45         str1=r.top();
    46         r.pop();
    47         int u=str1.v;
    48         if(vis[u]) continue;
    49         vis[u]=1;
    50         //printf("%d %lld
    ",u,dis[u]);
    51         for(int i=head[u]; i!=-1; i=e[i].nex)
    52         {
    53             int v=e[i].v;
    54             //printf("   %d
    ",v);
    55             ll a=e[i].a,b=p[e[i].b];
    56             if(a/dis[u]+1<b) continue;
    57             if(dis[v]>a+dis[u])
    58             {
    59                 dis[v]=a+dis[u];
    60                 r.push(shudui1(v,dis[v]));
    61             }
    62         }
    63     }
    64     if(dis[n]>=inf) printf("-1
    ");
    65     else
    66     {
    67         double x=log2(dis[n]);
    68         printf("%d
    ",(int)x);
    69     }
    70 }
    71 int main()
    72 {
    73     ll n,m;
    74     p[0]=1;
    75     for(ll i=1; i<=60; i++)
    76         p[i]=(ll)p[i-1]*(ll)2;
    77     ll t;
    78     scanf("%lld",&t);
    79     while(t--)
    80     {
    81         tot=0;
    82         scanf("%lld%lld",&n,&m);
    83         for(ll i=0; i<=n; i++)
    84         {
    85             vis[i]=0;
    86             dis[i]=inf;
    87         }
    88         memset(head,-1,sizeof(head));
    89         ll x,y,b,a;
    90         for(ll i=0; i<m; i++)
    91         {
    92             scanf("%lld %lld %lld %lld",&x,&y,&a,&b);
    93             add(x,y,a,b);
    94         }
    95         JK(1,n);
    96     }
    97     return 0;
    98 }
    View Code
  • 相关阅读:
    c++异常处理
    循环数比较
    交错01串
    六一儿童节
    独立的小易
    牛客网上的最后一位
    微微信.NET 为什么採用文件系统而不是数据库?
    Ugly Numbers(1.5.8)
    xcode6-beta下载
    接收socket数据的粘包处理
  • 原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/12709122.html
Copyright © 2011-2022 走看看