第三十届ACM/ICPC 世界总决赛题目解析

第三十届ACM/ICPC 世界总决赛题目解析

斯坦福大学 王颖

本次比赛的题目请见http://icpc.baylor.edu/icpc/Finals/2006WorldFinalProblemSet.pdf

Problem A

本题的大意是,给出一些机票,每个机票都是一条路线,比如城市A->城市B->城市K->…->城市N,并且每张机票有一个价格。我们可以只用一张机票的一部分,比如城市A->城市B->城市K,然后就丢弃这张机票。但有两个条件,第一,必须在机票的起始城市才能使用机票,也就是说,我们不能用上面的机票从城市B到城市K;第二,如果使用了一张机票的部分,以后就不能使用剩下的部分。

现在给出一条路线,我们要按顺序访问一系列的城市。给出所有可以购买的机票,每种机票可以买无限张,问怎样可以用最少的花费完成整个旅途。

 

本题的数据规模颇小,机票最多20种,而每个机票最多经过10个城市。由于机票可以重复购买,城市必须按顺序经过,很容易想到要用动态规划。但从比赛过程中可以发现,无数的队伍被这题卡住了,而且很少的队伍能够一次通过。问题就在于,并不是只能访问指定路径上的城市,而是可以访问一些辅助的城市来减小花费。所以,我们要用一个二元组(i,j)来表示一个状态。其中i表示指定路径上已经按顺序访问了的城市数量,j表示当前所在城市。通过机票的信息,不难得到状态之间的一个有向图,而我们要求的其实就是一个最短路径。注意到这个图是有圈的,所以我们不能直接用动态规划,而是需要用最短路算法。本题初看觉得规模甚小,此时则可以发现最多能有20*10=200个城市,共可以有10*200=2000个状态,还是颇有规模的。

 

总结:想清楚后此题并不复杂。但比赛时必须保持头脑清醒,分析清楚题意,才可能顺利解决此题。比赛中虽然很多队伍做出此题,但很少有队伍一次做对,更有一些队伍一直困在这题,可见比赛中队伍普遍紧张,没能仔细的去考虑。

 

Problem B

典型的最小费用最大流,不多说了。二分图匹配也可以,但得到的图规模太大。

 

Problem C

物理题,恐怕还需要不少计算几何。比赛的时候没人做,我也没仔细看。

 

Problem D

题目大意:形如a…ab…b的数叫做bipartite number,比如12223339999995088881等等都是。给出一个数字x(x<=99999),求出x的最小的倍数n=kx(k>1),使得nbipartite number

 

这是一道比较tricky的题目。比较容易想到的方法是,长度为pbipartite number很有限,最多有p*9*10个,可以一直枚举上去,直到得到x的倍数。但编程试验一下就会发现,有时候直到上千位也没出现x的倍数。主要问题在于,如果x的末尾是0,那么n的末尾也必须是0。比如x=99990,那么n会形如aa…a0,而且aa…a9999的倍数,这时候,只有一个自由度,所以我们可以期望得到的答案的长度是O(x)的。此时如果我们还用枚举所有bipartite number的方法,最多可能枚举90*(9999^2)/2个数,时间上不能接受。

解决这个问题的办法是,可以看到此时末尾已经确定,所以我们只需要枚举前面的部分,这个是可以在O(x)的时间内完成的,可以接受。但出现了另一个问题,末尾究竟有几个0?有人可能认为,x的末尾有几个0n的末尾就有同样数量的0。这是错误的。不妨考虑x=250,任何形如a…a0 (a>0)的数都不是250的倍数。因为a只可能等于5,而55不是25的倍数。所以,n的末尾可能还需要更多的0。经过分析不难发现,如果x末尾的0都去掉后还是16或者25的倍数,则我们需要更多的0。而当x248的倍数,或者5的倍数的时候,额外的0并不是一定需要的,但可能使得解更小。此时我们需要枚举0的个数,不过最多枚举3种情况,时间上完全可以接受。

x不是10的倍数的时候,bipartite numberx的余数可以看成是均匀分布的,此时直接枚举我们可以期望在O(x)的时间内得到解。我编程试验过,对于x不是10的倍数的情况直接枚举几乎不需要时间。但是,为了保证得到的是最小解,必须注意枚举的顺序。

 

总结:一道很考验选手综合素质的题目。严谨的数学上的分析,对各种细节的处理,还有编程实现上的技巧都是非常必要的。上面的分析虽然很长,一旦想清楚了程序可以写得很短。

 

思考题:为什么这样的bipartite number一定存在?

 

Problem E

题目大意:给出一个01串和一个压缩方法:把所有连续的1替换成其长度的二进制表示,只要这样的替换能够缩短字符串。比如1111101110010就会变成1010110010。现在给出压缩后的串(长度<=40),和压缩前的串长(<=16000)还有1的个数,问解码方法是否唯一。

 

可以动态规划。虽然原串中1的数量可能很多,但0的数量最多40个。所以状态最多16000*40*40个,而其中的大部分状态都不会出现。要注意的一点是,得到的原串不但要保证01的数量正确,也要保证能压缩的片段都被压缩了。

 

这题的规模不大,也可以考虑搜索。这样需要一些剪枝。这题各种剪枝的方法很多,但要做到在时限内得出正确结果也不容易。

 

Problem F

我没理解题目,看不懂齿轮的契合方式。感觉上是搜索或者解方程之类的题目。比赛的时候没什么人做,也没人做对。

 

Problem G

题目大意:Jack带了一帮人去朝圣。Jack是管钱的,他会遇到四种操作:paycollectinoutpay就是付一定数量的钱,collect是从让每人交一定数量的钱,in是新加入若干人,每个人要交当前总钱数/当前总人数这么多钱。out是离开若干人,每个人拿走当前总钱数/当前总人数这么多钱。注意,inout的时候,可能出现每个人平均的钱是分数的情况。题目中说,假设Jack很幸运,每次都正好整除了,问他开始可能带了多少人。

 

这题看似不好下手,不过我们可以认真的分析。不难发现会出问题的只是inout这两种操作。假设第一次inout(不妨假设是in p)的时候,我们有n个人,平均每个人的钱是k,那么in p之后,我们有n+p个人,每个人的钱还是kcollect操作不影响当前的整除性。不妨假设接下来两个操作分别是pay qin t,那么pay q后有n+p个人,每个人的钱是k-q/(n+p)。这必须是整数,因为下一个操作是in。所以n+p必须是q的约数,从而n只可能有有限个。

 

从上面的分析不难得出结论,如果我们把inout叫做critical operation,那么问题有有限个解当且仅当至少存在一个pay operation夹在两个critical operation之间。

 

我们可以不断重复上面的步骤,把所有连续的critical operation之间的pay都合并起来(注意,collect操作对整除性没有任何影响),然后得出一系列整除式,每个都是形如(n+a)|b。不需要去求解整个系统,n一定是b-a的约数,所以对一个式子求出所有约数,然后代入其它式子检验即可。

 

这个算法似乎太简单了一点,比赛中不应该只有这么少的队伍做对。或许有些地方我没考虑到,大家不妨指正。

 

Problem H

似乎是一道挺麻烦的折纸题,比赛的时候没人做。

 

Problem I

送分题。求两两间最短路中最长的一个。简单的floyd算法,放在topcoder绝对5分钟内一堆人做出来了。

 

Problem J

题目大意:给出一个有向图和两个点s1,s2,求一个最小的顶点的子集,使得在这个子集induce的子图中这两个点相互可达。

其实可以看成是我们要选择两条路径,一条从s1s2,另一条从s2s1,使得路径上出现的顶点数量最少。首先,s1s2必须在子集中。让S(v1,v2)表示要使得v1,v2强连通必须选择的除v1,v2外的顶点个数,d(v1,v2)表示丛v1v2的最短路,那么显然S(v1,v2)<=d(v1,v2)+d(v2,v1)-2,因为如果两条最短路径没有重合的顶点,那么出现的顶点总数就是d(v1,v2)+d(v2,v1)-2。考虑有重合顶点的情况,不妨假设中间有一个点t,那么要让v1,v2强连通,我们可以让v1,t强连通并且t,v2强连通,所以S(v1,v2)<=S(v1,t)+S(v2,t)+1。如果让T=S(v1,v2)+1,那么T(v1,v2)<=T(v1,t)+T(v2,t)。这看起来难道不熟悉么?这个就是说,我们可以把T(v1,v2)看成v1,v2间的一种最短路径。

这样算法就变得清晰了,先用floyd算法求出d(i,j),然后让T(i,j)=d(i,j)+d(j,i)-1,再用一次floyd算法更新T(i,j)的值,最后的答案就是T(s1,s2)+1。整个算法的主体部分不超过10行代码。

 

 

总结

A,B,D,E,G,I都是属于“较好做”的题目,J属于算法性强的一道图论题,剩下三题不太好说难度,但至少不常规。Final中大家还是很谨慎的,不会轻易去做一道不常规的题,也不会轻易去做别人没做对过的题。虽然最后冠军是6题,但我觉得如果一些队伍其实有做出7题的实力。Final这样的比赛,还是很看发挥。

A,B,D,E,G,I6题中,I属于必对题,B属于基本题,A有一点trick,但也应该做对;DE略为复杂,各有一些陷阱,但也属于该做对的题目。G只要仔细分析其实很简单。J题如果想出了算法,写程序只是5分钟的事。当然了,比赛中要做到这些,远比一个没有压力的旁观者分析的要难得多。

剩下的C,F,H三题基本没人做,我现在没有太多的时间所以也没细看,如果有人有想法请说出来吧。

 

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
ACM/ICPC(ACM International Collegiate Programming Contest, 国际大学生程序设计竞赛)是由国际计算机界历史悠久、颇具权威性的组织ACM(Association for Computing Machinery,国际计算机协会)主办的,世界上公认的规模最大、水平最高的国际大学生程序设计竞赛,其目的旨在使大学生运用计算机来充分展示自己分析问题和解决问题的能力。该项竞赛从1970年举办至今已历29届,一直受到国际各知名大学的重视,并受到全世界各著名计算机公司的高度关注,在过去十几年中,APPLE、AT&T、MICROSOFT和IBM等世界著名信息企业分别担任了竞赛的赞助商。可以说,ACM国际大学生程序设计竞赛已成为世界各国大学生最具影响力的国际级计算机类的赛事,是广大爱好计算机编程的大学生展示才华的舞台,是著名大学计算机教育成果的直接体现,是信息企业与世界顶尖计算机人才对话的最好机会。   该项竞赛分区域预赛和国际决赛两个阶段进行,各预赛区第一名自动获得参加世界决赛的资格,世界决赛安排在每年的3~4月举行,而区域预赛安排在上一年的9~12月在各大洲举行。   ACM/ICPC的区域预赛是规模很大、范围很广的赛事。仅在2003年参加区域预赛的队伍就有来自75个国家(地区),1411所大学的3150支代表队,他们分别在127个赛场中进行比赛,以争夺全球总决赛的73个名额,其激烈程度可想而知。 2005年第30届ACM/ICPC亚洲赛区预赛共设了北京、成都、汉城、东京等11个赛站,来自亚洲各国知名高校的各个代表队进行了激烈的角逐。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值