【Toll!Revisited(uva 10537)】
题目来源:蓝皮书P331
·这道题使得我们更加深刻的去理解Dijkstra!
在做惯了if(dis[u]+w<dis[v])的普通最短路后,这道选择路径方案不是简单的比大小的题横在了我们的面前。
·英文题,述大意:
一个无向图,读入起点终点以及各条边的两个端点。读入load,要求从起点开始运输,能够向终点运送load个物品。节点分为两种:城镇节点会每20个单位的货物收取一个单位的货物作为过路费(注意23个货物会收2个单位的物品作为过路费),乡村节点无论你带多少都只收取1个单位的货物。让你求出从起点出发最少携带多少货物,在经历层层苛刻收费后能够使到达终点的货物有load个(终点也要收费,起点不收费)。最后需要打印字典序最小的最优解路径。(n<=52,即大小写字母总个数,大写表示城镇,小写表示乡村)
·小小分析:
想办法调整最短路算法的路径选取策略。首先要保证最短路,但关键在于怎样计算到城镇的货物情况。由于不了解在起点带多少,却知道在终点剩多少,所以以终点为最短路源点,同样启用d[i]表示到达i点时至少要携带多少货物,使得走向终点后剩余货物保持为load个。
如果u是乡村,那就直接d[v]和d[u]+1比较即可。
如果u是城镇,那就值得思考:
考虑正常运输时,如果现在有k个货物,那么进入城市,则会变成多少个货物呢:rest=k-(k+19)/20[注意除号就是整除]。而现在由于最短路是倒推,所以我们只知道rest,要去求最小的k。必须保证均为正数,所以第一个不错而且容易考虑的方案就是二分。见下Dichotomy函数:
(x即上文的rest,mid即二分枚举的k)
·所以对于最短路的处理方式很简单,如果我们设节点:1~26为城镇,
27~52为乡村(这样便于字典序排序),在使用一个p[]来存前继结点,一切都变得美妙起来了:(图为Dijkstra部分)
最后进行一个倒序输出,就美妙至极了。
#include<stdio.h>
#include<queue>
#include<math.h>
#include<cstring>
#define go(i,a,b) for(int i=a;i<=b;i++)
#define fo(i,a,x) for(int i=a[x],v=e[i].v;i>-1;i=e[i].next,v=e[i].v)
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
using namespace std;const int N=102;struct E{int v,next;}e[N*N*2];
struct Q{int u;ll d;bool operator<(const Q& a)const{return d>a.d;}};
int ID(char u){int id;id='a'<=u&&u<='z'?u-'a'+27:u-'A'+1;return id;}
char DI(int u){char di;di=(1<=u&&u<=26)?'A'+u-1:'a'+u-27;return di;}
int n,head[N],k,t,S,T,p[N];ll inf=1,load,dis[N];bool vis[N];
void ADD(int u,int v){e[k]=(E){v,head[u]};head[u]=k++;}
ll dichotomy(ll x)
{
ll l=0,r=x*2+1,mid,res;
while(l<=r)mid=l+r>>1,mid-(mid+19)/20>=x?res=mid,r=mid-1:l=mid+1;
return res;
}
int main()
{
freopen("in.in","r",stdin);
go(i,1,14)inf*=10;while(scanf("%d",&n),++t,~n)
{
mem(head,-1);k=0;go(i,1,n)
{char u,v;scanf(" %c %c ",&u,&v);ADD(ID(u),ID(v));ADD(ID(v),ID(u));}
char a,b;scanf("%lld %c %c",&load,&a,&b);T=ID(a);S=ID(b); priority_queue<Q>q;mem(vis,0);
go(i,1,52)dis[i]=inf;p[S]=-1;
dis[S]=load;q.push((Q){S,dis[S]});
while(!q.empty())
{
Q x=q.top();q.pop();int u=x.u;if(vis[u])continue;vis[u]=1;
fo(i,head,u)
{
ll least=u<=26?dichotomy(dis[u]):dis[u]+1;
if(least<dis[v])dis[v]=least,p[v]=u,q.push((Q){v,dis[v]});
if(least==dis[v])u<p[v]?p[v]=u:1;
}
}
printf("Case %d:\n%lld\n",t,dis[T]);int u=T;printf("%c",DI(u));
while(p[u]>0)printf("-%c",DI(p[u])),u=p[u];printf("\n");
}
return 0;
}//Paul_Guderian
但还有一美妙之事需要提一提:
对于求城镇的least,有O(1)的方法。如果把你手中的货物20个20个地分组,那么可以分成这样:
那么如果你经过了一个城市,然后就变成了这样(20-1=19):
·你肯定知道a<=20:那么可以美妙地变形:
a<=20
20a-19a<=20
20(a-1)<=19a
(a-1)*(20/19)<=a ————Paul
注意观察左边那一坨,是什么意思?
和上文一样,进城前是k,进城后是rest。那么:
上图中如果给图二中每一个数给它乘一个(20/19),那么:
所有的19全变成了20,a-1变成了(a-1)*(20/19),此时的式子可以简写为:rest*(20/19)[你难道忘记了上文的rest和k?]
好的,仔细关注上文被”Paul”标记的不等式,我们豁然开朗:
rest*(20/19)<=k
要求k的最小值,就是左边的结果向上取整就可以了,即:
将上面程序中的least=dichotomy(…)改成:
代码其他地方没有变:
1 #include<stdio.h>
2 #include<queue>
3 #include<math.h>
4 #include<cstring>
5 #define go(i,a,b) for(int i=a;i<=b;i++)
6 #define fo(i,a,x) for(int i=a[x],v=e[i].v;i>-1;i=e[i].next,v=e[i].v)
7 #define mem(a,b) memset(a,b,sizeof(a))
8 #define ll long long
9 using namespace std;const int N=102;struct E{int v,next;}e[N*N*2];
10 struct Q{int u;ll d;bool operator<(const Q& a)const{return d>a.d;}};
11 int ID(char u){int id;id='a'<=u&&u<='z'?u-'a'+27:u-'A'+1;return id;}
12 char DI(int u){char di;di=(1<=u&&u<=26)?'A'+u-1:'a'+u-27;return di;}
13 int n,head[N],k,t,S,T,p[N];ll inf=1,load,dis[N];bool vis[N];
14 void ADD(int u,int v){e[k]=(E){v,head[u]};head[u]=k++;}
15 int main(){go(i,1,14)inf*=10;while(scanf("%d",&n),++t,~n)
16 {
17 mem(head,-1);k=0;go(i,1,n)
18 {char u,v;scanf(" %c %c ",&u,&v);ADD(ID(u),ID(v));ADD(ID(v),ID(u));}
19 char a,b;scanf("%lld %c %c",&load,&a,&b);T=ID(a);S=ID(b);
20 priority_queue<Q>q;mem(vis,0);go(i,1,52)dis[i]=inf;p[S]=-1;
21 dis[S]=load;q.push((Q){S,dis[S]});while(!q.empty())
22 {
23 Q x=q.top();q.pop();int u=x.u;if(vis[u])continue;vis[u]=1;
24 fo(i,head,u)
25 {
26 ll least=u<=26?(ll)ceil(dis[u]*1.0/19*20):dis[u]+1;
27 if(least<dis[v])dis[v]=least,p[v]=u,q.push((Q){v,dis[v]});
28 if(least==dis[v])u<p[v]?p[v]=u:1;
29 }
30 }
31 printf("Case %d:\n%lld\n",t,dis[T]);int u=T;printf("%c",DI(u));
32 while(p[u]>0)printf("-%c",DI(p[u])),u=p[u];printf("\n");
33 }return 0;}//Paul_Guderian
我们在未知的道路上行走,流着坚强的泪水放荡并且迷惘。————汪峰《觉醒》
【Toll!Revisited(uva 10537)】的更多相关文章
- The Toll! Revisited UVA - 10537(变形。。)
给定图G=(V,E)G=(V,E),VV中有两类点,一类点(AA类)在进入时要缴纳1的费用,另一类点(BB类)在进入时要缴纳当前携带金额的1/20(不足20的部分按20算) 已知起点为SS,终点为TT ...
- 【习题 4-9 UVA - 815】Flooded!
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 题目很迷啊. 不会出现盆地? 可以理解为一条线. 从左往右高度上升的一座座山. 然后V升的水从最左边的山倒进去. 然后问你最后海拔多 ...
- 【习题 4-8 UVA - 12108】Extraordinarily Tired Students
[链接] 我是链接,点我呀:) [题意] [题解] 一个单位时间.一个单位时间地模拟就好. 然后对于每个人. 记录它所处的周期下标idx 每个单位时间都会让每个人的idx++ 注意从醒着到睡着的分界线 ...
- 【习题 4-7 UVA - 509】RAID!
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 如果一行里面某位有>1个x 那么是invalid的. 没有x的话. 可以分析以下(设输入的标准Even为0,然后Odd为1) ...
- 【习题 4-6 UVA - 508】Morse Mismatches
[链接] 我是链接,点我呀:) [题意] 给你每个字母对应的摩斯密码. 然后每个单词的莫斯密码由其组成字母的莫斯密码连接而成. 现在给你若干个莫斯密码. 请问你每个莫斯密码对应哪个单词. 如果有多个单 ...
- 【习题 4-4 UVA - 253】Cube painting
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 绕(x,y,z)三个轴旋转. 枚举x,y,z各4次的结果. (4次之后能还原.可以方便上一层枚举下一个情况.) [代码] #incl ...
- 【习题 4-3 UVA - 220】Othello
[链接] 我是链接,点我呀:) [题意] [题解] legal被我打成leagal... 然后注意输出坐标的时候,格式是%2d.. 然后就没啥难的了.. [代码] #include <bits/ ...
- 【例题 4-5 uva 512】Spreadsheet Tracking
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 每个操作对与一个点来说变化是固定的. 因此可以不用对整个数组进行操作. 对于每个询问,遍历所有的操作.对输入的(x,y)进行相应的变 ...
- 【例题 4-4 uva 213】Message Decoding
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 输入的二进制长度最长为7 所以得开个sta[7][2^7]的样子才存的下所有的字符的.. 定义这么一个数组当字典. 然后一个字符一个 ...
随机推荐
- Struts2之Struts2的标签库
前言: Struts2提供了大量的标签 ,用来帮助开发表现层页面,这些表现一方面解决了美观性的需求,因为它们具有html标签一样的外观,另一方面它们解决了功能性的需求, 因为它们具有jsp脚本一样的逻 ...
- mingw打dll ,lib包命令和调用
1,下面的命令行将这个代码编译成 dll. gcc mydll.c -shared -o mydll.dll -Wl,--out-implib,mydll.lib 其中 -shared 告诉gcc d ...
- python 类的绑定方法和非绑定方法
一.绑定方法 1.对象的绑定方法 首先我们明确一个知识点,凡是类中的方法或函数,默认情况下都是绑定给对象使用的.下面,我们通过实例,来慢慢解析绑定方法的应用. class People: def __ ...
- SpringMvc返回报文形式的控制-验证方法: JSON or HTML or XML
首先,请求通过accept请求头声明了支持的返回格式 然后,框架根据该请求头和代码实现(注解)选择了对应的MessageConverter处理返回! 一.验证过程 1.返回html 1.1.请求组装 ...
- Spark快速入门
Spark 快速入门 本教程快速介绍了Spark的使用. 首先我们介绍了通过Spark 交互式shell调用API( Python或者scala代码),然后演示如何使用Java, Scala或者P ...
- 详解k8s零停机滚动发布微服务 - kubernetes
1.前言 在当下微服务架构盛行的时代,用户希望应用程序时时刻刻都是可用,为了满足不断变化的新业务,需要不断升级更新应用程序,有时可能需要频繁的发布版本.实现"零停机"." ...
- (Sqlyog或Navicat不友好处)SHOW ENGINE INNODB STATUS 结果为空或结果为=====================================
因为最近在学习innodb引擎,所以就在自己的sqlyog上执行上述命令: SHOW ENGINE INNODB STATUS 结果显示如下: 换了个客户端navicat,执行如下: 最后登录到服务器 ...
- python基础-循环
循环 循环 要计算1+2+3,我们可以直接写表达式: >>> 1 + 2 + 3 6 要计算1+2+3+...+10,勉强也能写出来. 但是,要计算1+2+3+...+10000,直 ...
- POJ-1511 Invitation Cards---Dijkstra+队列优化+前向星正向反向存图
题目链接: https://vjudge.net/problem/POJ-1511 题目大意: 给定节点数n,和边数m,边是单向边. 问从1节点出发到2,3,...n 这些节点路程和从从这些节点回来到 ...
- 字符串分割方法split()函数
>>> data = '1000,小甲鱼,男'>>> data.split(',')['1000', '小甲鱼', '男'] str.split('以什么为标志进行 ...