画圆的沙滩

亦简亦美

2011年4月4日 #

找符合条件的数

摘要: 编程之美2.8节。大略看了一下作者的解答。作者的解法有点动态规划的套路。这里尝试用广搜的办法来求解。在我们做乘法时,最低位的数字决定于乘数的最低位,而与乘数的高位无关。广搜的策略就是从低到高逐位尝试,直到找到结果。注意下面的代码中vis数组的使用。这个数组可以使广搜树得到有效剪枝。本来STL中vector<bool>的特化是被很多人批评的一件事,这里却恰是我想要的结果,不仅速度快,还可以有效节省空间。struct Item { int v; string s; Item(int vv, const string& ss): v(vv), s(ss) {}};bool bfs 阅读全文

posted @ 2011-04-04 13:35 acmaru 阅读(229) 评论(0) 推荐(0) 编辑

2011年3月31日 #

线性序列的最优化

摘要: 这与编程之美的4.5节磁带文件的存放优化有关。原题要求使得所有的平均访问长度最短,而存放序列是线性的。事实上,这是一个排序问题。我们从排序问题本身来看。假设我们已经有一个序列:58976231。我们的目标是使得由这些数字构成的值最小。这是一个显然的排序问题。不过,这里换一个角度来看待它。我们采用局部优化的方式来解决这个问题。首先,对于任意相邻的两个数字ab,如果a < b,显然就有 ab < ba。为了使问题能更一般化一些,假设无法进行简单的a,b比较, 我们如何再进行排序呢?比如说在原题的情况下,我们就无法简单对两个文件进行比较。换一个思路,考虑这两个文件构成的序列,我们是可以评 阅读全文

posted @ 2011-03-31 18:08 acmaru 阅读(216) 评论(0) 推荐(0) 编辑

2011年3月30日 #

买书问题

摘要: 编程之美1.4节。这是一道很有趣的问题。作者试图使用贪心策略去解答,尽管给出了贪心中关键的变化,不过最终并没有给出证明。然后,解法二中使用了动态规划来求解这道题。另外,新版中提到薛笛有更细致一点的分析:http://blog.csdn.net/kabini/archive/2008/04/16/2296943.aspx,其中主要讨论了贪心算法。不过,我感觉仍然不够简明清晰。确实,这道题是可以使用贪心的。关键是如何应用贪心策略,从而保证可以到达最优解。下面给出我的理解。首先,类似于作者的思路,可以试图分解较小的数找到最佳的分解组合。不过,这里作者和薛笛关注的方向不恰当。事实上,对于任意的组合数, 阅读全文

posted @ 2011-03-30 12:15 acmaru 阅读(169) 评论(1) 推荐(0) 编辑

最近点对问题

摘要: 编程之美2.11节。也可参考:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=113&page=show_problem&problem=1186对于扩展问题2,可以先找到这些点的凸包(O(nlogn)),然后对凸包点求最大距离。对于凸包点,可以考虑按长轴平分四份,然后在最外侧的两份之间寻找最大点对。因为居内侧的两份中的最大距离无法超过长轴。当然,可以分割得更精细一点。这只是计算上复杂性的小差别了。struct Point { double x, y;}; 阅读全文

posted @ 2011-03-30 09:28 acmaru 阅读(310) 评论(0) 推荐(0) 编辑

2011年3月25日 #

查询最近和与最大最小值

摘要: 编程之美2.12节。可参考http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=113&page=show_problem&problem=1428关于扩展问题,先考虑三个数的情形:首先排序,如果所有数都小于sum/3或者大于sum/3,那么肯定不会有解。不妨考虑存在小于等于sum/3的情形,可以肯定<=sum/3的数中必定要取一个。在取定了一个<=sum/3的数之后,我们可以在大于这个数的范围内寻找剩下的两个数,这时问题即转化为了初始问题。对于任意 阅读全文

posted @ 2011-03-25 10:11 acmaru 阅读(197) 评论(0) 推荐(0) 编辑

2011年3月23日 #

有意义的电话号码

摘要: 编程之美的作者把3.2节的难度设定为三星,私下以为在二星左右。书中的解法二即最简版的深搜实现。而解法一实际是在枚举。事实上,这个问题十分类似于anagram问题。关于anagram问题,编程珠玑上有很细致的讨论。如果有兴趣的话,也可以尝试下面这道题:http://poj.org/problem?id=1002关于枚举的实现,我还是更喜欢实现一个类似于next_permutation的方法,然后用do...while循环来遍历。bool next_number(vector<int>& digits, const vector<int>& ranges) 阅读全文

posted @ 2011-03-23 20:41 acmaru 阅读(257) 评论(0) 推荐(0) 编辑

平面的切割

摘要: 这是一个有趣的问题。编程之美1.7节进行了探讨。其中解法二的思路非常巧妙。其用到的找逆序数算法是merge sort的变形,也很常见。最后的代码是这个算法的一份实现。这里则要从一个不同的角度来考虑这个问题。作者在分析分割的区域时,得到了这样的公式: F = N+M+1,其中N为直线数,M为交点数。作者的思路简明清晰。这里则要采用另外一个思路来给出这个公式。考虑著名的欧拉公式:F = E - V + 2。我们可以假想两条垂线在无穷远处重合,从而构成一个长轴是无穷大的椭圆区域,如下面的图所示。只考虑区域内的线段,再将区域外想象成为一个面,则整个图形构成一个压平的多面体。其顶点就是这些线条的交点,边 阅读全文

posted @ 2011-03-23 18:23 acmaru 阅读(301) 评论(0) 推荐(0) 编辑

区间覆盖

摘要: 编程之美2.19节,写了一份实现。对于扩展问题,可以使用一个平面四叉树来维护被覆盖的部分,对于每一个查询的矩形,在树中查询是否有空隙。这个过程同建树的过程中,插入一个新矩形是一致的。在建四叉树的时候,注意合并那些完全覆盖的子树成为叶节点。当然,我觉得用k-d树来维护覆盖信息也可以。template<class T>struct Interval { T a, b; bool operator<(const Interval& other) const { return a < other.a || a == other.a && b > o 阅读全文

posted @ 2011-03-23 15:44 acmaru 阅读(195) 评论(0) 推荐(0) 编辑

最短摘要与反转链表

摘要: 关于最短摘要,编程之美3.5节并没有给出详细的代码。其实还是值得一写的。下面的实现我使用了set和map来维护相关的信息。int main() { int n, m; while (cin>>n>>m) { // input vector<string> seq; while (n--) *back_inserter(seq) = *istream_iterator<string>(cin); set<string> kwords; while (m--) *inserter(kwords, kwords.end()) = *istr 阅读全文

posted @ 2011-03-23 11:34 acmaru 阅读(194) 评论(0) 推荐(0) 编辑

2011年3月22日 #

分割数组

摘要: 编程之美2.18节。作者的代码很精练,可惜解释不太清晰。虽然代码只有三个for语句,可是头两个for语句不可以随意置换。而且,第二个for语句必须是以递减的方式计算。取i个元素求和,把这些和构成一个集合。我们只记录<=sum/2的和,则最多可以获得n/2个集合S(i)。在构造S(i)的时候,可以使用S(i-1)中的和加上一个未使用的元素v[k]来构造。每多一个新元素,这些集合就可以扩张一次,这两个for循环的含义也即在此。如果使用set来维护这些集合,由于自动忽略了重复的元素,算法实际上并不会达到O(2^n)的复杂度,最多为O(n^2*sum),即解法三的复杂度。而且,由于使用的是set 阅读全文

posted @ 2011-03-22 15:29 acmaru 阅读(290) 评论(0) 推荐(0) 编辑

导航