博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
NEU 1664 传送(最短路基础 堆优化Dijkstra)
阅读量:4498 次
发布时间:2019-06-08

本文共 5427 字,大约阅读时间需要 18 分钟。

题目描述

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 23 3 1 2 35 3 2 3 4

样例输出

13 思路:把区域当做节点,穿过某个区域抽象成路过某个节点,进入该节点话费为ai,出节点免费,链接点和区域,然后以目标点(中间点)为原点做一遍单源最短路,我用的是Dijkstra,最后时间为7000+ms,空间为50000kb+,空间还好,是提交的里面几乎最小的,但是时间很不满意,应该还有更好的方法,知道了来更新。 (update001:下面这个是错误代码,不要参考)
1 #include
2 #include
3 #include
4 #include
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 str11 {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 strdis25 {26 int x;27 long long dis;28 bool operator<(const strdis& a)const{
return dis
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 else79 {80 printf("%lld\n",dis[s]+dis[t]);81 }82 }83 84 return 0;85 }
Dijkstra

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

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

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

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

 

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

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

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

1 #include
2 #include
3 #include
4 #include
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 str11 {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 strdis25 {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
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!\n");74 }75 else76 {77 printf("%lld\n",dis[s]+dis[t]);78 }79 }80 81 return 0;82 }

 

转载于:https://www.cnblogs.com/xuwangzihao/p/5181402.html

你可能感兴趣的文章
lua -- 生成协议
查看>>
HLP帮助文件源文件RTF文件的编写
查看>>
2.30模型字符串拷贝
查看>>
XPATH怎么获取TITLE中有中文的标签
查看>>
Tomcat中server.xml参数说明
查看>>
Wget下载终极用法和15个详细的例子
查看>>
JavaScript16进制颜色值和rgb的转换
查看>>
Laravel 输出Hellow World!
查看>>
【bzoj 十连测】[noip2016十连测第九场]Problem B: 小P的单调区间(最长上升子序列+树状数组)...
查看>>
linux--samba
查看>>
django基础之中介模型
查看>>
关于副本机制
查看>>
Oracle之存储过程
查看>>
解决电脑复选框图标不正确方法
查看>>
伪数组怎么转为真正的数组呢~
查看>>
WebGL笔记(六):简单灯光
查看>>
JavaScript利用数组原型,添加方法实现遍历多维数组每一个元素
查看>>
ASP.NET生成缩略图
查看>>
“NASA”计划背后_阿里巴巴大数据系统架构概述
查看>>
oracle 查询树结构节点下的数量
查看>>