• NEU 1664 传送(最短路基础 堆优化Dijkstra)


    题目描述

    A最近喜欢上一款游戏:游戏把地图分了一些区域,这些区域可能会重叠,也可能不会。

    游戏中有一项传送技能,改传送技能只能将在同一区域的两个地方使用。小A可以利用区域中重叠部分来实现从某一区域到另一个区域的移动。

    当然技能会消耗魔法值,对于同一区域内两点,消耗的魔法值是相同的。如下图:

    有红蓝两个区域,共4个地点1 2 3 4,假设在红色区域移动只需消耗a1点魔法值,在蓝色区域间移动需花费a2点魔法值,那么12之间或者13之间都需花费a1点魔法,24或者34之间都需要a2点魔法,23之间选择消耗a1点魔法也可以选择消耗a2点魔法。

    现在小AS点接到了一个任务,需要到达F点去做任务,再到P点交任务。

    现在让你求一下完成该任务,需要因为传送消耗的魔法值至少为多少。

    当然有些地方需要花RMB才能到达,即你从S点无论如何也无法到达F点去做任务,或者F点无法到达P点。因为双11,小A已经没有RMB了,这是你只需告诉他“Poor guy, you don’t have enough Money!”。

    输入

    多组样例输入(不会超过10组)

    对于每一组样例:

    第一行有五个整数 n m S F P 表示有n个地点和m个区域(2<=n<=100000)    (0<m<1000000)S F P为题目中所述的地点编号。(地点编号为:1,2,3......,n).

    接下来每行描述的是每一个区域的信息,

    ai bi 表示 在第i块区域内需要消耗ai点魔法值,第i各区域有bi个地点,然后有bi个数,代表第i个区域内第地点编号。(1<=ai<=1000000000, bi>0) .

    保证所有bi的和小于1000000.

    输出

    如果无解,则输出“Poor guy, you don’t have enough Money!”(引号中的内容)。

    否则就输出最少的消耗的魔法量。

    样例输入

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

    样例输出

    13

    思路:把区域当做节点,穿过某个区域抽象成路过某个节点,进入该节点话费为ai,出节点免费,链接点和区域,然后以目标点(中间点)为原点做一遍单源最短路,我用的是Dijkstra,最后时间为7000+ms,空间为50000kb+,空间还好,是提交的里面几乎最小的,但是时间很不满意,应该还有更好的方法,知道了来更新。
    (update001:下面这个是错误代码,不要参考)
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<queue>
     4 #include<cstring>
     5 const int maxl=2000009;
     6 const int maxn=2000000;
     7 using namespace std;
     8 int n,m,s,t,p;
     9 int lin[maxn],cnt=0;
    10 struct str
    11 {
    12     int y;
    13     int z;
    14     int next;
    15 }e[maxl];
    16 void insert(int x,int y,int z)
    17 {
    18     cnt++;
    19     e[cnt].next=lin[x];
    20     lin[x]=cnt;
    21     e[cnt].y=y;
    22     e[cnt].z=z;
    23 }
    24 struct strdis
    25 {
    26     int x;
    27     long long dis;
    28     bool operator<(const strdis& a)const{return dis<a.dis;}
    29     void set(int xx,int diss){x=xx;dis=diss;}
    30 }temp,noww;
    31 //bool operator <(const strdis &a,const strdis &b){return a.dis<b.dis;}
    32 priority_queue <strdis> q;
    33 bool vis[maxn];
    34 long long dis[maxn];
    35 int main()
    36 {
    37     while(scanf("%d%d%d%d%d",&n,&m,&s,&p,&t)!=EOF)
    38     {
    39         memset(lin,0,sizeof(lin));cnt=0;
    40         memset(vis,0,sizeof(vis));
    41         for(int i=1;i<=m;i++)
    42         {
    43             int ai,bi,x;
    44             scanf("%d%d",&ai,&bi);
    45             for(int j=1;j<=bi;j++)
    46             {
    47                 scanf("%d",&x);
    48                 insert(x,n+i,ai);
    49                 insert(n+i,x,0);
    50             }
    51         }
    52         temp.set(p,0);
    53         q.push(temp);
    54         memset(dis,0x3f,sizeof(dis));
    55         dis[p]=0;
    56         while(!q.empty())
    57         {
    58             noww=q.top();
    59             q.pop();
    60             int nn=noww.x;
    61             if(vis[nn])continue;
    62             vis[nn]=1;
    63             for(int i=lin[nn];i;i=e[i].next)
    64             {
    65                 int u=e[i].y;
    66                 if(dis[u]>dis[nn]+e[i].z)
    67                 {
    68                     dis[u]=dis[nn]+e[i].z;
    69                     temp.set(u,dis[u]);
    70                     q.push(temp);
    71                 }
    72             }
    73         }
    74         if((!vis[s])||(!vis[t]))
    75         {
    76             printf("Poor guy, you don't have enough Money!
    ");
    77         }
    78         else
    79         {
    80             printf("%lld
    ",dis[s]+dis[t]);
    81         }
    82     }
    83 
    84     return 0;
    85 }
    Dijkstra

    提交了五次,前两次是忘记去掉打表。。。第三次是复制粘贴的答案字符串里面有不对的字符,第四次是重定义符号弄反了,第五次是没有看到多组数据。

    恩,re小王子又回来了。。。。要注意。

    哦,既然写了Dijkstra,就要说下如何堆优化,

    其实不用担心如何更新堆里边dis的值,没必要,只需要把新的值push进去就好了,因为访问次优的时候,那个点已经vis过了。。。就是空间上浪费点儿。。。不知道怎么解决

    update-------------------------------------------------------------------------------------2016.02.11

    我的代码比别人的慢四倍,自己怎么找都找不到问题,学长一下就看了出来。。。

    原来的代码有一个符号错了,就是重定义小于号那里,因为默认是大根堆,也就是最大的先出来,我们需要最短的,于是需要反着定义

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<queue>
     4 #include<cstring>
     5 const int maxl=2000009;
     6 const int maxn=2000000;
     7 using namespace std;
     8 int n,m,s,t,p;
     9 int lin[maxn],cnt=0;
    10 struct str
    11 {
    12     int y;
    13     int z;
    14     int next;
    15 }e[maxl];
    16 void insert(int x,int y,int z)
    17 {
    18     cnt++;
    19     e[cnt].next=lin[x];
    20     lin[x]=cnt;
    21     e[cnt].y=y;
    22     e[cnt].z=z;
    23 }
    24 struct strdis
    25 {
    26     int x;
    27     long long dis;
    28     bool operator<(const strdis& a)const{return dis>a.dis;}
    29 }noww;
    30 //bool operator <(const strdis &a,const strdis &b){return a.dis<b.dis;}
    31 priority_queue <strdis> q;
    32 bool vis[maxn];
    33 long long dis[maxn];
    34 int main()
    35 {
    36     while(scanf("%d%d%d%d%d",&n,&m,&s,&p,&t)!=EOF)
    37     {
    38         memset(lin,0,sizeof(lin));cnt=0;
    39         memset(vis,0,sizeof(vis));
    40         for(int i=1;i<=m;i++)
    41         {
    42             int ai,bi,x;
    43             scanf("%d%d",&ai,&bi);
    44             for(int j=1;j<=bi;j++)
    45             {
    46                 scanf("%d",&x);
    47                 insert(x,n+i,ai);
    48                 insert(n+i,x,0);
    49             }
    50         }
    51         q.push((strdis){p,0});
    52         memset(dis,0x3f,sizeof(dis));
    53         dis[p]=0;
    54         while(!q.empty())
    55         {
    56             noww=q.top();
    57             q.pop();
    58             int nn=noww.x;
    59             if(vis[nn])continue;
    60             vis[nn]=1;
    61             for(int i=lin[nn];i;i=e[i].next)
    62             {
    63                 int u=e[i].y;
    64                 if(dis[u]>dis[nn]+e[i].z)
    65                 {
    66                     dis[u]=dis[nn]+e[i].z;
    67                     q.push((strdis){u,dis[u]});
    68                 }
    69             }
    70         }
    71         if((!vis[s])||(!vis[t]))
    72         {
    73             printf("Poor guy, you don't have enough Money!
    ");
    74         }
    75         else
    76         {
    77             printf("%lld
    ",dis[s]+dis[t]);
    78         }
    79     }
    80   
    81     return 0;
    82 }
  • 相关阅读:
    location.replace与location.href,location.reload的区别
    转载关于KeyPress和KeyDown事件的区别和联系
    Javascript中call的使用
    按值和按引用的比较
    理解cookie的path和domain属性
    HTML的快速写法:Emmet和Haml
    SVN标准命令
    linux常用命令
    Android4.0(Phone)拨号启动过程分析(一)
    Activity生命周期
  • 原文地址:https://www.cnblogs.com/xuwangzihao/p/5181402.html
Copyright © 2020-2023  润新知