显示标签为“算法”的博文。显示所有博文
显示标签为“算法”的博文。显示所有博文

2009-04-13

UVa 3n+1 问题

UVa 3n+1 问题
1.       问题描述
编号 :100.
简单描述 : 就是对一个整数 ( 大于等于 1), 不断按照这样的规律进行运算 , 即如果当前数是偶数 , 则下一个数为当前数除以 2, 如果当前数为奇数 , 则下一个数为当前数乘 31, 整个过程直到计算到 1 为止 . 那么形成的数列的长度称为 cycle-length.
问题的输入是 : 给定一个区间 [a,b]
问题的输出为 : 输出给定区间 ( 含端点 ) 所以数的 cycle-length 的最大的 cycle-length.
详细描述可参见 这里 .
2.       问题分析
            2.1    直观分析
最直观的方法当然是采用蛮力法 (brute-force), 将给定区间的每个数求出其 cycle-length, 然后在所以的 cycle-length 中找出最大的即可 .
            2.2    优化
优化是建立在分析的基础之上 .
我们先对一个简单例子进行实验 .
例如给定区间为 B[1,10],1,2,3,4,5,6,7,8,9,10
通过简单分析我们可以知道 , 通常较大的数具有较大的 cycle-length, 所以我们可以首先取 A=9( 为什么不取 10, 是因为 9 在一次处理后可变为 28, 大于 10) 按照给定的规律来进行如下 :
9 28 14 7 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1
可以看出 , 上面红色标记的部分 , 处于给定的区间内 , 而且它们的 cycle-length 显然是小于当前的数 9cycle-length, 所以这些数可以从给定的区间内剔除掉 , 记住当前的 cycle-length, 于是
经过一次的操作后 , 给定的区间变为 3,6
继续按照这个方法进行 , 直至这个区间为空 , 停止 , 其中最大的 cycle-length 即为所求 .
            2.3    得出算法
算法的描述同 2.2 处优化部分的分析 , 具体的算法描述可见 3.
3.       算法描述
算法伪代码 (C) 描述如下 :
function getMCL
B[left, right];  // 为给定的区间
mcl = 0;               //mclmax-cycle-length
while !B.empty()
{
A = getCandidate(B);// 这个函数是用来找出 B 区间内当前最适合处理的元素 ,
// 一般是最大的奇数 , 即预计可能具有较大 cycle-length 的元素
                     ccl = 1;          //ccl 是指 current-cycle-length
                     while (A!=1)
              {
                     ccl++;
                     A = (A%2)?(3*A+1):(A/2);
                     if find(B,A)           // 这个函数是用来判断 B 区间内是否存在中间结果 A
                            pop(B,A);       // 有则剔除
              }
              mcl = (mcl<ccl)?ccl:mcl;
       }
       return mcl;
 
4.       具体实现
Cpp代码
  1. #include "iostream"  
  2. using namespace std;  
  3.   
  4. int getCandidate(int B[], int base, int n)  
  5. {  
  6.     int i;  
  7.     for (i = n-1; i>=0; i--)  
  8.     {  
  9.         if (((base+i) % 2)&&(B[i]==0))  
  10.             return i;  
  11.     }  
  12.     for (i = n-1; i>=0; i--)  
  13.     {  
  14.         if (!B[i])  
  15.             return i;  
  16.     }  
  17.     return -1;  
  18. }  
  19. int nadd2(int left, int right)  
  20. {  
  21.     int Blength = right - left + 1;  
  22.     int length = Blength;  
  23.     int *B = new int[length];  
  24.     for (int i=0; i<length; i++)  
  25.         B[i] = 0;  
  26.     int mcl = 0;  
  27.     while (length > 0)  
  28.     {  
  29.         int ccl = 1;  
  30.         int pos = getCandidate(B, left, Blength);  
  31.         if (pos==-1)  
  32.             break;  
  33.         B[pos] = 1;  
  34.         length--;  
  35.         int A = pos+left;  
  36.         while (A!=1)  
  37.         {  
  38.             ccl ++;  
  39.             A = (A%2)?(3*A+1):(A/2);  
  40.             int Apos;  
  41.             if ((A-left>Blength)||(B[A-left])||(A<left))  
  42.                 Apos = -1;  
  43.             else  
  44.                 Apos = A-left;  
  45.                   
  46.             //B[Apos] = 1;  
  47.             if (Apos!=-1)  
  48.             {  
  49.                 B[Apos] = 1;  
  50.                 length --;  
  51.             }  
  52.         }  
  53.         mcl = (mcl<ccl)?ccl:mcl;  
  54.     }  
  55.     delete[] B;  
  56.     return mcl;  
  57. }  
  58. int main()  
  59. {  
  60.     int left, right;  
  61.     while(cin>>left>>right)  
  62.         cout<<left<<" "<<right<<" "<<nadd2(left,right)<<endl;  
  63.     return 0;  
  64. }  
 
5.       复杂性分析
主要的耗时部分是二层循环部分 , 而外层循环的次数主要取决于内层循环在区间内的命中率 . 没有进行过统计学的分析 , 但只要 candidate 选取合适 , 每次内层循环会有大于 50% 的命中率 .
假设区间内数 A 的内层循环次数 ( 即由 A 按照规则变为 1cycle-length)X, 平均命中率为 p, 那么时间复杂度为 :
T(n) = X*T(n*(1-p))     // 其中 X 为平均的 cycle-length
6.       备注
在实现过程中 , 最初使用的是 C++ 中的 vector, 但运行时的实际耗时比使用数组的蛮力法还要长 , 经过分析 , 这是因为编译器在维护 vector 这个数据结构时所耗时长是比较大的 , 特别是当使用 vectorearse 方法来删除某个特定元素时 . 所以最后还是使用最基本的数组来实现 , 用标记来指示删除状态 .
所以在实际的算法实现中 , 数据结构的选取也是非常重要的 , 所谓的程序 = 算法 + 数据结构是也 .
可以改进的地方包括有 :getCandidate 函数的算法 , 即如何预估一个具有较长 cycle-length 的元素 ; 还有当内层循环出现在区间内已标记为删除状态的元素中时 , 这时内层循环可终止 .

字符匹配问题(1)――Rabin-Karp算法

字符串匹配问题( 1 )—— Rabin-Karp 算法
1.       问题描述
给定目标字符串 T[0..n-1] (基于 0 的数组,数组长度为 n ),和模式串 P[0..m-1] ,问 P 可否匹配 T 中的任意子串,如果可以,返回匹配位置。
2.       问题分析
            直观分析
brute-force 的蛮力法,适用于较小规模的字符串匹配。
            优化
主要介绍 3 种优化办法,分别具体为: Rabin-Karp 算法,有限自动机和 KMP 算法。将分为 3 篇博文分别讨论。本小节主要介绍 Rabin-Karp 算法。
            得出算法
Rabin-Karp 算法(以下简称为 RK 算法),是基于这样的思路:即把串看作是字符集长度进制的数,由数的比较得出字符串的比较结果。例如,给定字符集为∑ ={0,1,2,3,4,5,6,7,8,9} ,∑长度为 d=10 ,那么任何以∑为字符集的串都可看作 d (此处为 10 )进制的数。
记模式串 P[0..n-1] 对应的数值为 PT[0..n-1] 所有长度为 m 的子串对应的数值为 ts ,设 PT 都是基于字符集长度为 ||=d 的字符串。
那么, ts 即为 T[s..s+m] 对应的数值,这里 0<=s<=n-m-1
P = P[m]+d*(P[m-1]+d*(P[m-2]+..)))
同样 t0 也可类似求得。
最重要的是如何从 ts 求出 ts+1
ts+1 =T[s+m]+d*(ts +dm-1 *T[s])
注:此处是该算法的关键,即在常数时间内能够计算出下一个 m 长度的字串对应的数值。初看比较抽象,举个例子就比较明白了,设 x=12345 ,现在是已知长度为 3 的数值 234 ,现在要求 345 对应的数值,可以这样来得到: 345 = 5 + 10*(234-102 *2)
3.       算法描述
求出所有 m 长度子串所对应的数值,对数值进行比较,继而得出子串是否匹配。当模式串长度很大时,这时对应的数值会很大,比较起来比较麻烦,可使用对一个大奇数取模后进行比较。
4.       具体实现
       这里实现的只是m值较小时的情形,大整数需要特定的类的支持(如可自定义大整数类),选取10进制的数是为了方便起见,当然字母也是OK的。

Cpp代码
  1. #include "iostream"  
  2. #include "string"  
  3. #include "cmath"  
  4. using namespace std;  
  5.   
  6. // get the value of the character in the set   
  7. int getV(char p, string set)  
  8. {  
  9.     for(int i=0; i<set.length(); i++)  
  10.     {  
  11.         if (p==set[i])  
  12.             return i;  
  13.     }  
  14.     return -1;  
  15. }  
  16. // d is the size of the character set  
  17. int RK(string T, string P,string set)  
  18. {  
  19.     int d = int(set.length());  
  20.     int n = T.length();  
  21.     int m = P.length();  
  22.     int h = pow(double(d), m-1);  
  23.     int p=0;  
  24.     int t = 0;  
  25.     for(int i=0; i<m; i++)  
  26.     {  
  27.         p = d*p + getV(P[i],set);  
  28.         t = d*t + getV(T[i], set);  
  29.     }  
  30.     for (int s=0; s<=n-m; s++)  
  31.     {  
  32.         cout<<"p,t is "<<p<<","<<t<<endl;  
  33.         if (p==t)  
  34.             return s;  
  35.         if (s<n-m)  
  36.             t = getV(T[s+m],set)+d*(t-h*getV(T[s],set));  
  37.     }  
  38.     return -1;  
  39. }  
  40. int main()  
  41. {  
  42.     // set is the character set  
  43.     string set= "0123456789";  
  44.     // pattern P  
  45.     string P = "2365";  
  46.     // T is the string to match  
  47.     string T = "258569236589780";  
  48.     int i = RK(T, P, set);  
  49.     cout<<"the postition is:"<<i<<endl;  
  50.     return 0;  
  51. }  
 

  5.       参考资料
[1]   Thomas H. Cormen Introduction to Algorithms

2009-04-12

[ZZ]ACM基本算法分类、推荐学习资料和配套pku习题

ACM基本算法分类、推荐学习资料和配套pku习题

.动态规划

参考资料:

刘汝佳《算法艺术与信息学竞赛》《算法导论》

推荐题目:

http://acm.pku.edu.cn/JudgeOnline/problem?id=1141

简单

http://acm.pku.edu.cn/JudgeOnline/problem?id=2288

中等,经典TSP问题

http://acm.pku.edu.cn/JudgeOnline/problem?id=2411

中等,状态压缩DP

http://acm.pku.edu.cn/JudgeOnline/problem?id=1112

中等

http://acm.pku.edu.cn/JudgeOnline/problem?id=1848

中等,树形DP可参考《算法艺术与信息学竞赛》动态规划一节的树状模型

http://acm.zju.edu.cn/show_problem.php?pid=1234

中等,《算法艺术与信息学竞赛》中的习题

http://acm.pku.edu.cn/JudgeOnline/problem?id=1947

中等,《算法艺术与信息学竞赛》中的习题

http://acm.pku.edu.cn/JudgeOnline/problem?id=1946

中等,《算法艺术与信息学竞赛》中的习题

http://acm.pku.edu.cn/JudgeOnline/problem?id=1737

中等,递推

http://acm.pku.edu.cn/JudgeOnline/problem?id=1821

中等,需要减少冗余计算

http://acm.zju.edu.cn/show_problem.php?pid=2561

中等,四边形不等式的简单应用

http://acm.pku.edu.cn/JudgeOnline/problem?id=1038

较难,状态压缩DP,《算法艺术与信息学竞赛》中有解答

http://acm.pku.edu.cn/JudgeOnline/problem?id=1390

较难,《算法艺术与信息学竞赛》中有解答

http://acm.pku.edu.cn/JudgeOnline/problem?id=3017

较难,需要配合数据结构优化(我的题目^_^

http://acm.pku.edu.cn/JudgeOnline/problem?id=1682

较难,写起来比较麻烦

http://acm.pku.edu.cn/JudgeOnline/problem?id=2047

较难

http://acm.pku.edu.cn/JudgeOnline/problem?id=2152

难,树形DP

http://acm.pku.edu.cn/JudgeOnline/problem?id=3028

难,状态压缩DP,题目很有意思

http://acm.pku.edu.cn/JudgeOnline/problem?id=3124

http://acm.pku.edu.cn/JudgeOnline/problem?id=2915

非常难

.搜索

参考资料:

刘汝佳《算法艺术与信息学竞赛》

推荐题目:

http://acm.pku.edu.cn/JudgeOnline/problem?id=1011

简单,深搜入门题

http://acm.pku.edu.cn/JudgeOnline/problem?id=1324

中等,广搜

http://acm.pku.edu.cn/JudgeOnline/problem?id=2044

中等,广搜

http://acm.pku.edu.cn/JudgeOnline/problem?id=2286

较难,广搜

http://acm.pku.edu.cn/JudgeOnline/problem?id=1945

难,IDA*,迭代加深搜索,需要较好的启发函数

http://acm.pku.edu.cn/JudgeOnline/problem?id=2449

难,可重复K最短路,A*可参考解题报告:

http://acm.pku.edu.cn/JudgeOnline/showcontest?contest_id=1144

http://acm.pku.edu.cn/JudgeOnline/problem?id=1190

难,深搜剪枝,《算法艺术与信息学竞赛》中有解答

http://acm.pku.edu.cn/JudgeOnline/problem?id=1084

难,《算法艺术与信息学竞赛》习题

http://acm.pku.edu.cn/JudgeOnline/problem?id=2989

难,深搜

http://acm.pku.edu.cn/JudgeOnline/problem?id=1167

较难,《算法艺术与信息学竞赛》中有解答

http://acm.pku.edu.cn/JudgeOnline/problem?id=1069

很难

. 常用数据结构

参考资料:

刘汝佳《算法艺术与信息学竞赛》

《算法导论》

线段树资料:

http://home.ustc.edu.cn/~zhuhcheng/ACM/segment_tree.pdf

树状数组资料

http://home.ustc.edu.cn/~zhuhcheng/ACM/tree.ppt

关于线段树和树状数组更多相关内容可在网上搜到

后缀数组资料

http://home.ustc.edu.cn/~zhuhcheng/ACM/suffix_array.pdf

http://home.ustc.edu.cn/~zhuhcheng/ACM/linear_suffix.pdf

推荐题目

http://acm.pku.edu.cn/JudgeOnline/problem?id=2482

较难,线段树应用,《算法艺术与信息学竞赛》中有解答

http://acm.pku.edu.cn/JudgeOnline/problem?id=1151

简单,线段树应用矩形面积并,《算法艺术与信息学竞赛》中有解答

http://acm.pku.edu.cn/JudgeOnline/problem?id=3225

较难,线段树应用,可参考解题报告

http://acm.pku.edu.cn/JudgeOnline/showcontest?contest_id=1233

http://acm.pku.edu.cn/JudgeOnline/problem?id=2155

难,二维树状数组。

http://acm.pku.edu.cn/JudgeOnline/problem?id=2777

中等,线段树应用。

http://acm.pku.edu.cn/JudgeOnline/problem?id=2274

难,堆的应用,《算法艺术与信息学竞赛》中有解答

http://acm.zju.edu.cn/show_problem.php?pid=2334

中等,左偏树,二项式堆或其他可合并堆的应用。

左偏树参考 http://www.nist.gov/dads/HTML/leftisttree.html

二项式堆参见《算法导论》相关章节

http://acm.pku.edu.cn/JudgeOnline/problem?id=1182

中等,并查集

http://acm.pku.edu.cn/JudgeOnline/problem?id=1816

中等,字典树

http://acm.pku.edu.cn/JudgeOnline/problem?id=2778

较难,多串匹配树

参考: http://home.ustc.edu.cn/~zhuhcheng/ACM/zzy2004.pdf

http://acm.pku.edu.cn/JudgeOnline/problem?id=1743

难,后缀数组

http://acm.pku.edu.cn/JudgeOnline/problem?id=2774

较难,最长公共子串,经典问题,后缀数组

http://acm.pku.edu.cn/JudgeOnline/problem?id=2758

很难,后缀数组

可参考解题报告

http://acm.pku.edu.cn/JudgeOnline/showcontest?contest_id=1178

http://acm.pku.edu.cn/JudgeOnline/problem?id=2448

很难,数据结构综合运用

.图论基础

参考资料:

刘汝佳《算法艺术与信息学竞赛》《算法导论》《网络算法与复杂性理论》谢政

推荐题目:

http://acm.pku.edu.cn/JudgeOnline/problem?id=2337

简单,欧拉路

http://acm.pku.edu.cn/JudgeOnline/problem?id=3177

中等,无向图割边

http://acm.pku.edu.cn/JudgeOnline/problem?id=2942

较难,无向图双连通分支

http://acm.pku.edu.cn/JudgeOnline/problem?id=1639

中等,最小度限制生成树,《算法艺术与信息学竞赛》中有解答

http://acm.pku.edu.cn/JudgeOnline/problem?id=2728

中等,最小比率生成树,《算法艺术与信息学竞赛》中有解答

http://acm.pku.edu.cn/JudgeOnline/problem?id=3013

简单,最短路问题

http://acm.pku.edu.cn/JudgeOnline/problem?id=1275

中等,差分约束系统,Bellman-Ford求解,《算法艺术与信息学竞赛》中有解答

http://acm.pku.edu.cn/JudgeOnline/problem?id=1252

简单,Bellman-Ford

http://acm.pku.edu.cn/JudgeOnline/problem?id=1459

中等,网络流

http://acm.pku.edu.cn/JudgeOnline/problem?id=2391

较难,网络流

http://acm.pku.edu.cn/JudgeOnline/problem?id=1325

中等,二部图最大匹配

http://acm.pku.edu.cn/JudgeOnline/problem?id=2226

较难,二部图最大匹配

http://acm.pku.edu.cn/JudgeOnline/problem?id=2195

中等,二部图最大权匹配

KM算法参考《网络算法与复杂性理论》

http://acm.pku.edu.cn/JudgeOnline/problem?id=2516

较难,二部图最大权匹配

http://acm.pku.edu.cn/JudgeOnline/problem?id=1986

中等,LCA(最近公共祖先)问题

参考Tarjan's LCA algorithm 《算法导论》第21章习题

http://acm.pku.edu.cn/JudgeOnline/problem?id=2723

较难,2-SAT问题

参考:http://home.ustc.edu.cn/~zhuhcheng/ACM/2-SAT.PPT

http://acm.pku.edu.cn/JudgeOnline/problem?id=2749

较难,2-SAT问题

http://acm.pku.edu.cn/JudgeOnline/problem?id=3164

较难,最小树形图

参考《网络算法与复杂性理论》中朱-刘算法

.数论及组合计数基础

http://acm.pku.edu.cn/JudgeOnline/problem?id=1811

简单,素数判定,大数分解

参考算法导论相关章节

http://acm.pku.edu.cn/JudgeOnline/problem?id=2888

较难,Burnside引理

http://acm.pku.edu.cn/JudgeOnline/problem?id=2891

中等,解模方程组

http://acm.pku.edu.cn/JudgeOnline/problem?id=2154

中等,经典问题,波利亚定理

http://cs.scu.edu.cn/soj/problem.action?id=2703

难,极好的题目,Burnside引理+模线性方程组

http://acm.pku.edu.cn/JudgeOnline/problem?id=2764

较难,需要数学方法,该方法在《具体数学》第七章有讲

http://acm.pku.edu.cn/JudgeOnline/problem?id=1977

简单,矩阵快速乘法

算法分析基础

这块需要注意如下几个问题:
  1. 时间复杂度的精确定义:是指程序运行的对应指令数。
  2. 通常使用的渐近分析法(如O, omega, theta),最常用的是最块情况分析
  3. master theorem

2009-04-07

算法学习计划

学习算法是持续性的学习过程,当然这次主要有两个目的,一个是自己真的到了好好思索、整理下算法相关知识的时候了,另一个就是为了暑期后的找工作。所以制定了一份算法学习计划,来督促自己完成整个算法的学习和总结。

学习计划:
  1. 算法分析基础 04/06-04/12
  2. 排序 04/13-04/19
  3. 数据结构1(基本的数据结构,hash表,二叉查找树)04/20-04/26
  4. 数据结构2(红-黑树,前缀树,B树,后缀树等) 04/27-05/03
  5. 动态规划和贪婪算法 05/04-05/10
  6. 平摊分析(Amortized Analysis)和堆(二项堆,Fibonacci堆等)05/11-05/17
  7. 图论1 05/18-05/24
  8. 图论2 05/25-05/31
  9. 排序网络,矩阵操作,线性编程 06/01-06/07
  10. 多项式和FFT, 数论算法 06/08-06/14
  11. 字符匹配,计算几何,NP相关 06/15-06/21
  12. 近似算法及其它 06/22-06/28


相关说明:
  • 学习周期:2009-04-06至2009-06-28
  • 整个学习过程以《算法导论》为蓝本,并辅以诸如wikipedia,其他的算法书籍
  • 一周一个专题,并且为每周的算法学习和总结写一篇日志
  • 严格遵守本学习计划
  • 学习对应的习题可参考两部分:算法导论习题及UVaSphere