算法作业相关总结

第一次算法作业共十题,包括简单的定积分求值、不等式证明、算法原理分析、搜索有序表、八皇后拓展、素数判定,主要是概率算法的掌握。

对某些问题确定性算法求解起来时间很长,而概率算法则能相对容易求得正确结果,如快速排序随机划分问题、八皇后求解问题、判断大整数是否伪素数问题。

概率算法分为数字算法、Mente Carlo算法、Las Vegas算法、Sherwood算法,其中MC算法不管正确与否总是给出一个结果,LV算法不返回错误的答案但有时根本找不到答案,MC和LV算法找到正确结果的概率正比于算法执行时间。Sherwood算法总是给出正确的答案,通常可以消除好坏实例之间的差别,用于当算法解决问题的平均时间远小于最坏时间。

作业1,2,3均为数字概率算法。作业5估计集合X的势的概率算法。作业7是sherwood算法搜索有序数组问题。作业9求n=12~20最优StepVegas值利用LV算法和确定性回溯算法相结合。作业10用MC算法求100~10000以内错误素数(即强伪素数)的比例。

其中:

作业5当n足够大(2^31)时,估计的n与实际n相差太大。尝试提高随机数的范围但错误率仍然很大,估计是算法本身不合理的问题。

作业7有序表通过两个序列确定, 分别是val和ptr,如下所示:

      i      1     2     3     4     5     6      7

val[i]      2     3    13    1     5     21    8

ptr[i]      2     5     6     1     7     0      3

rank       2     3     6     1     4     7      5

head=4    有序表:1,2,3,5,8,13,21     

采用shuffle()方法对val序列进行随机处理,保证最后通过ptr能按照从小到大顺序正确输出val序列的元素。

具体以

i    1 2 3 4 5

val 1 2 3 4 5

ptr 2 3 4 5 0

为例,如果i=1和i=2的列交换,则

i    1 2 3 4 5

val 2 1 3 4 5

ptr 3 1 4 5 0

继续交换,如果i=2和i=3的列交换,则

i    1 2 3 4 5

val 2 3 1 4 5 

ptr 2 4 1 5 0

注意到这两种交换即为shuffle()随机处理过程中典型的两类列交换,分别是"序列两端任一端和序列中间元素交换"与"序列中间任两列元素交换"。以第一种交换为例,val交换的元素为第1和第2列,所以在ptr中找值为1和2的,并将值为2的重新赋值为1,值为1的重新赋值为2,如果没找到值为1或2的则不作处理。算法采用vector实现ptr,利用algorithm中的find()方法找出ptr中指定元素的下标位置并重新赋值,从而实现通过ptr即可按序输出val。find()元素也能找出val中第一个元素的位置,即为ptr中值为1的下标对应的val元素。

算法A为O(n)的确定算法,B为O(sqrt(n))的确定算法,算法D为概率算法。shuffle()耗时很多,对于顺序序列,算法B的表现和A一样差。随机算法D表现时好时坏。算法C表现始终很好。对于随机序列,算法B和算法C表现都很好,速度很快。而算法A效果要差。随机算法D表现时好时坏,算法具体运行的时间差别并不是很明显。

作业9根据搜索过的平均节点数确定最优的StepVegas,最终当n=8(八皇后)时结果比较合理,当n=12~20随着随机放置的马的数量增大,算法的成功率迅速降低为0,导致最后的结果很不合理。怀疑是由于当n增大时生成的随机数随机效果不好导致算法成功率迅速降低,没有被验证。

作业10由于求素数的算法为3/4正确、偏假的MC算法,导致当迭代次数为2~4时选出强伪素数的概率为(1-3/4)^(2~4),比较低的概率导致在100~10000中产生错误素数的比例很小。当改为迭代一次时,概率为1-3/4=1/4此时在100~10000中产生错误素数的比例稍微有所增加,也验证了MC算法迭代次数越多求出正确结果概率越大的结论。

其中作业5求集合大小的算法(求指正):

1 SetCount (X) {
2   k ← 0; S ← Ф;
3   a ← uniform(X);
4   do {
5   k++;
6   S ← S∪{a}; a ← uniform(X);
7   } while (a not in S)
8   return 2k2/π
9 }

其中作业7的shuffle()算法:

vector<int> Shuffle(int *val, vector<int> ptr, int n)
{
    srand(time(0));
    int i = 1, j = 1, k = 1, st = (int)sqrt(n*1.0);
    vector<int>::iterator ir,jr;
    for(; i < st; i++)
    {
        j = (rand()%(n-1) + 1);
        Swap(val, i, j);
        ptr = SwapVector(ptr, i, j);
        ir = find(ptr.begin(),ptr.end(),i);
        jr = find(ptr.begin(),ptr.end(),j);
        if(ir != ptr.end()){
            ir = ptr.erase(ir,ir+1);//清除ptr中为i的值
            ptr.insert(ir,j);//增加j
        }
        if(jr != ptr.end()){
            jr = ptr.erase(jr,jr+1);
            ptr.insert(jr,i);
        }
    }
    return ptr;
}

 作业9截图:

 

生成超出32767(2^15-1)的随机数方法:

1.rand()*rand()

2.rand()*1.0/RAND_MAX*n (n>32767)

3.对有m位数字的n,用随机生成每一位上的数字乘以对应的10的k次幂(k为该数字所在的位数,以321为例,3对应的k为2),最后相加

4.rand()<<16 + rand()

5.参考头文件里面的rand()函数,重写该函数

6.线性同余,x2 = ((x1 * 1103515245) + 12345) & 0x7fffffff,这个同余式可以[0, 2147483647]上随机。

 

其中1,3可能导致生成的随机数不是很随机。在windows下,RAND_MAX的值为32767(0x7fff),在linux下,RAND_MAX的值则是最大的32位正整数:2147483647(2的31次方减1:0xffffffff,该数也是欧拉发现的一个梅森素数)。其中6,线性同余参见http://www.cnblogs.com/xkfz007/archive/2012/03/27/2420154.html

对于5:

参见:http://www.oschina.net/code/explore/cygwin-1.7.7-1/newlib/libc/stdlib/rand_r.c

参见http://blog.csdn.net/ammana_babi/article/details/1437498

 1 #include <stdlib.h>
 2 
 3 /** Pseudo-random generator based on Minimal Standard by
 4    Lewis, Goodman, and Miller in 1969.
 5  
 6    I[j+1] = a*I[j] (mod m)
 7 
 8    where a = 16807
 9          m = 2147483647
10 
11    Using Schrage's algorithm, a*I[j] (mod m) can be rewritten as:
12   
13      a*(I[j] mod q) - r*{I[j]/q}      if >= 0
14      a*(I[j] mod q) - r*{I[j]/q} + m  otherwise
15 
16    where: {} denotes integer division 
17           q = {m/a} = 127773 
18           r = m (mod a) = 2836
19 
20    note that the seed value of 0 cannot be used in the calculation as
21    it results in 0 itself
22 */
23       
24 int
25 _DEFUN (rand_r, (seed), unsigned int *seed)
26 {
27         long k;
28         long s = (long)(*seed);
29         if (s == 0)
30           s = 0x12345987;
31         k = s / 127773;
32         s = 16807 * (s - k * 127773) - 2836 * k;
33         if (s < 0)
34           s += 2147483647;
35         (*seed) = (unsigned int)s;
36         return (int)(s & RAND_MAX);
37 }
 1 static long my_do_rand(unsigned long *value)
 2 {
 3    /*
 4       这个算法保证所产生的值不会超过(2^31 - 1)这里(2^31 - 1)就是 0x7FFFFFFF。
 5       而 0x7FFFFFFF等于127773 * (7^5) + 2836,7^5 = 16807。
 6       整个算法是通过:t = (7^5 * t) mod (2^31 - 1)
 7       这个公式来计算随机值,并且把这次得到的值,作为下次计算的随机种子值。
 8    */
 9    long quotient, remainder, t;
10    quotient = *value / 127773L;
11    remainder = *value % 127773L;
12    t = 16807L * remainder - 2836L * quotient;
13    if (t <= 0)
14       t += 0x7FFFFFFFL;
15    return ((*value = t) % ((unsigned long)RANDOM_MAX + 1));
16 }

两者最后return处理方式不同但效果相同。

 

关于GSL(GNU Scientific Library)库的利用:

http://gnailuy.com/2011/07/10/gsl%E7%A7%91%E5%AD%A6%E8%AE%A1%E7%AE%97%E5%BA%93%E3%80%81%E9%9A%8F%E6%9C%BA%E5%8F%98%E9%87%8F%E7%9A%84erlang%E5%88%86%E5%B8%83%E4%B8%8Eweibull%E5%88%86%E5%B8%83/

http://www.cnblogs.com/suda/archive/2012/03/03/2378644.html

http://blog.csdn.net/daiyuchao/article/details/2218039

 

posted @ 2013-12-03 23:24  Francis Fu  阅读(641)  评论(0编辑  收藏  举报