ACM UVa 算法题100, 101, 103, 104, 112, 10405解法

下面是我以前在我的Live Space的Blog上面写的一些ACM算法题目的解法,一次性贴出来供大家参考,也是对自己研究的一个记录。以后我做了新的题目会在CSDN Blog和我的Live Space Blog上面同时发布。
最近决定做一些ACM的题目来提高一下自己的算法的水平。N年(n>=6)没做这类型的题目了,手有点生疏了。网上有不少ACM的题目和Online Judge,UVa算是其中比较出名的一个。就从UVa开始做起吧。当时在学校就应该好好搞ACM的,可惜毕业之后才想起有ACM这回事 :(
Submit Program的几个注意事项:
  1. 输入输出直接从stdin/stdout,不用文件读写
  2. 可以接受一个输入立刻输出答案,不用全部记住答案然后一次性输出
  3. 最好用gcc/g++,避免Compile Error
  4. 注意IO结束条件是EOF还是其他的特殊值

这一道题看上去不难,直接一个一个硬算也可以得出答案。不过要快速得出答案自然需要用到Dynamic Programming,说白了就是要把中间结果记下来。用数组记当然最简单但是内存要求还是蛮大的,所以我先用map记了。算cycle number需要递归,我则是用的一个stack(vector)来去掉递归,先反复压栈直到答案已知,然后依次退栈计算。
程序写好了,提交上去居然是Compile Error? 看了一下网上的论坛,没找到什么有用的建议。试了一下#include老的.h的头文件依然Compile Error. 实在没有办法了,试着把int main(void)改成了int main(int argc, char *argv),居然通过了。可是我的gcc并没有报错啊?
Compile Error好了,接下来居然是Wrong Answer。奇怪,我试过了不少答案应该是正确的阿。试着考虑一下i>j的case,还是Wrong Answer。上Forum看看,发现好多人接连试过n次都是Wrong Answer,幸好有人指点说i>j的时候i j不应该交换顺序,而是原样输出。比如100 1输出还是要输出100 1,不能图方便直接交换变成1 100。晕,题目明明没有说清楚这些额外条件阿,难道要我们自己猜?改好了之后又修了一个Bug,终于Accepted。不过时间就。。。 似乎比他们直接计算然后比较最大值来的还慢,可能是我为了节省内存用了map导致要不断进行查找导致速度偏慢。如果用数组应该会改善不少。BTW,我看到这个题结果排名前面的不少人居然CPU运行时间是0!?? 就算再快也不可能快的这么离谱吧,会不会是他们预先把结果算好了然后直接输出了呢?
以后我会比较有规律的每个星期坚持做一些题目,然后把自己的解法Post出来。
开始101。这个题主要是模拟机器人移动方块,并不需要什么技巧。用一个list<int>作为stack来维护一堆积木的状态,用这样的一个vector来track每个位置的积木堆的状态。最后用一个pos的vector来track每个方块所在的位置。
刚开始的时候Wrong Answer,后来发现看错了题目要求,修改了一下便Accepted。这个题的通过率为25.7%,可能是题目要求比较容易出错导致的吧。


一个子问题是如何判断一个多维的盒子可以放在另外一个多维的盒子里面。其实只需要对各个维做一下排序然后依次顺序比较即可。
这个题目据我所知有两种方法:

方法1)

如果盒子a可以放置到盒子b中,则认为盒子a对应的节点a有一条边到盒子b对应的节点b。这样,问题转化为求All Pairs Longest Path。用动态规划可以解。
假定dist[i, j]是i到j的最大距离,则有

dist[i, j] = max { dist[i, r] + 1 | g[r, j] <> max }
计算Online Judge的Test Case用时0.088s

方法2)

比方法1快上不少。题目可以看成求严格递增的数字子序列(Longest Scattered Subsequence)。假定s[i] = 结束于i的子序列Ax1, Ax2, ... Axm, xm=i,于是有

s[i] = max { s[j] + 1 | A[j] < A[i] }

很典型的Bottom-Up Dynamic Programming.
计算Online Judge的Test Case用时0.010s,大概快9倍。

UVa - #104 - Arbitrage

前几天就已经做完了,但是一直没有时间来写。这道题说白了无非就是求具有最大权值之积的最短环路。所以最根本的还是直接应用Floyd-Warshall算法,因为本题需要求最短的环路,所以在问题空间用两维的f[i][j]是不够的,需要用到三维: f[i][j][step]。step指path的长度。在Floyd-Warshall算法的三层循环之外还需要一层step的循环,公式如下:

f[i][j][step] = max { f[i][k][step-1] * f[k][j][1] |f[k][j][1] <max}

这次的程序和上次的都有Presentation Error。尝试了一下之后发现我在最后一个结果后面多Output了一个空格,去掉就Accept了。


UVa - #112 - Tree Summing

其实是一个比较简单的题,有点奇怪为什么正确率那么低,可能大家忘了考虑负数了吧。Anyway,直接用递归下降法就可以解决。递归下降分析树结构的同时就相当于遍历了整棵树,因此无需在内存中把这棵树建立起来,而是在递归的时候同时累加,就可以知道是否存在这样的路径了。


UVa - #10405 - Longest Common Sub-Sequence

特意去找了这道题来做一下,巩固一下自己对此类算法的理解,顺便也试验了一下Bottom-up Dynamic Programming和Top-down Dynamic Programming的速度区别。一般来说,如果Bottom-Up Dynamic Programming没有计算很多没有用到的子问题的话,Bottom-Up Dynamic Programming要快于Top-Down的。这个题目比较搞的是,题目中完全没有提到字符串中居然会有空格......

作者 : ATField
E-Mail: [email protected]
Blog:
http://blog.csdn.net/atfield

你可能感兴趣的:(算法,F#,gcc,J#,UP)