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+,空间还好,是提交的里面几乎最小的,但是时间很不满意,应该还有更好的方法,知道了来更新。
 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!\n");
77         }
78         else
79         {
80             printf("%lld\n",dis[s]+dis[t]);
81         }
82     }
83 
84     return 0;
85 }
Dijkstra

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

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

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

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

你可能感兴趣的:(NEU 1664 传送(最短路基础 堆优化Dijkstra))