zoukankan      html  css  js  c++  java
  • 八皇后-递归

    八皇后-递归

    重写八皇后,最开始用双层循环,然后用递归重写,还是递归易懂,优雅

    复制代码
      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 #include <math.h>
      5 #include "stack_seq_generic.h"
      6 
      7 #define QUEEN 4
      8 
      9 typedef struct{
     10     int x;
     11     int y;
     12 } Point;
     13 
     14 BOOL in_border(int x){
     15     if (x>=0 && x<QUEEN) {
     16         return TRUE;
     17     }
     18     return FALSE;
     19 }
     20 
     21 BOOL can_place(SqStack *s, Point *p){
     22     Point *top = (Point *)s->top;
     23     Point *base = (Point *)s->base;
     24     
     25     if (!in_border(p->x) || !in_border(p->y)) {
     26         return FALSE;
     27     }
     28     
     29     while (base < top) {
     30         int x_dif = abs(p->x - base->x);
     31         int y_dif = abs(p->y - base->y);
     32         
     33         if (base->y==p->y || x_dif==y_dif) {
     34             return FALSE;
     35         }
     36         base++;
     37     }
     38     return TRUE;
     39 }
     40 
     41 static int count = 0;
     42 
     43 void print_queens(SqStack *s){
     44     Point *top = s->top;
     45     Point *base = s->base;
     46     
     47     char area[QUEEN][QUEEN] = {0};
     48     memset(area, '*', sizeof(char)*QUEEN*QUEEN);
     49     
     50     if (top - base >= QUEEN) {
     51         while (base < top) {
     52             area[base->x][base->y] = '#';
     53             base++;
     54         }
     55         
     56         int i,j;
     57         for (i=0; i<QUEEN; i++) {
     58             for (j=0; j<QUEEN; j++) {
     59                 printf("%c ", area[i][j]);
     60             }
     61             printf("
    ");
     62         }
     63         printf("
    ");
     64         
     65         count++;
     66     }
     67     
     68 }
     69 
     70 void queens_recursion(SqStack *s, Point p){
     71     if (can_place(s, &p)) {
     72         push(s, &p);
     73         print_queens(s);
     74         Point next = {p.x+1, 0};
     75         queens_recursion(s, next);
     76     }else{
     77         if (stack_empty(s)) {
     78             return;
     79         }
     80         
     81         if (!in_border(p.y) || !in_border(p.x)){
     82             pop(s, &p);
     83             Point next = {p.x, p.y+1};
     84             queens_recursion(s, next);
     85         }else{
     86             Point next = {p.x, p.y+1};
     87             queens_recursion(s, next);
     88         }
     89         
     90     }
     91 }
     92 
     93 int main(void){
     94     SqStack stack;
     95     init_stack(&stack, sizeof(Point));
     96     
     97     //queens(&stack);
     98     Point p = {0, 0};
     99     queens_recursion(&stack, p);
    100 
    101     printf("total:%d
    ", count);
    102     
    103     return 0;
    104 }
    复制代码

    8行代码解决约瑟夫问题

    首先是问题描述:

    约瑟夫斯问题(有时也称为约瑟夫斯置换),是一个出现在计算机科学和数学中的问题。在计算机编程的算法中,类似问题又称为约瑟夫环。

    n个囚犯站成一个圆圈,准备处决。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。

    问题是,给定了nk,一开始要站在什么地方才能避免被处决?

                                                                                                                                                                                                                                                     --摘自维基百科

    这么说可能比较抽象,我们举个例子:

    当n=5,k=3时,我们假设这5个人的序号分别为1、2、3、4、5。那么依次被杀掉的人是3、1、5、2,最后活下来的是4。

    接下来我们分析一下问题:

    我们先来做些准备工作:

    1.  我们把这个问题记为 f 。 f(n, k) 为问题的解。其中参数 n 和 k 的含义与问题描述中的一致。n 个人的序号分别为1、2、3...n。我们会得到最后剩下那个人的序号。

    2.  因为这个问题操作起来是环形的,所以我们可以这么认为:

            序号 0 和序号 n 是一样的、序号 -1 和序号 (n-1)  是一样的、 序号 -2 和序号 (n-2) 是一样的...

            同样,序号 (n+1)  和序号 1 是一样的、 序号 (n+2) 和序号 2 是一样的...

            也就是说,对 n 求模相等的数指向的是同一个人。但在给出最终结果时我们会进行处理,将结果映射在整数区间[1, n]内 。

    3.  对于给定的 n 和 k,第一个被杀掉的人是 k 。(k 有可能大于 n,但根据“准备工作2”,k 同样会指向正确的那个人)

    4.  f(1, 1) = 1。

    5.  将一个数 m, 按照“准备工作2”中的规则映射到整数区间[1, n]内可以这样操作: (m - 1)%n + 1 

    准备工作完毕。

    下面开始正式分析:

    我们可以根据 f(n-1, k)来快速得到 f(n, k):

        我们固定 k 值不变。

        假设 f(n-1, k) = r, 也就是说有 (n-1) 个人时, 活下来的那个人到起点的距离是 (r-1)。(起点那个人序号为1)

        那么,当人数为 n 时, 我们可以先杀掉一个人让人数变为 (n-1)。根据准备工作中的第三条,我们第一步先杀掉 k。这时新的起点变为了 (k+1),人数变为了 (n-1),活下来的那个人为 (k+1) + (r-1), 也就是 (f(n-1, k) + k)。

        我们还要把这个结果处理一下,根据“准备工作5”,处理后的结果为: (f(n-1, k) + k - 1)%n + 1

        最终得到的是: f(n, k) = (f(n-1, k) + k - 1)%n + 1

    分析完毕。

    最后用一种你喜欢的语言来实现你的分析结果:

    f(1, 1) = 1;

     f(n, k) = (f(n-1, k) + k - 1)%n + 1;

    这个就很简单了,你可以用递归,也可以用循环。用递归写起来简单,但执行起来比较消耗资源;循环相反。

    我在这里用scheme的尾递归实现。简单提一下scheme的尾递归,它书写上是递归的形式,但执行时解释器做了优化,不会保存上次的调用栈(因为这在尾递归中是不必要的),所以采用尾递归可以既写起来简单又不会太消耗资源。

    复制代码
    #lang scheme
    (define (f n k)
      (define (f-iter result counter)
        (if (> counter n)
            result
            (f-iter (add1 (modulo (+ result k -1) counter))
                    (add1 counter))))
      (f-iter 1 2))
    复制代码

    运行示例:

    > (f 5 3)
    4

    短短的几行代码就把问题解决了。这也告诉了我们在写代码前要先做两件事:

        1.  将问题分析透彻,减少不必要的计算量,也就是降低时间复杂度,节约计算机的时间。比如这个问题你也可以不用分析,直接让计算机去傻瓜式地挨个数,一直数到只剩最后一个。可能问题规模不大时,这种方法你还能忍受,一旦问题规模加大,线性时间复杂度和指数时间复杂度的区别还是挺大的。

        2.  选择一门合适的计算机语言,尽量快地完成任务,也就是节约自己的时间。同样的问题你也可以选择c语言,java或者其它,但我认为在这个问题的解决上scheme无疑是最优秀的。

    PS:

    也许对上面的结果还不太满意,因为上面只给出了最后剩下的人,你可能还想知道这些人的死亡顺序。我可以给出我写的升级版程序:

    复制代码
    #lang scheme
    (define (advanced-f prisoners k)
      (define (new-list lst p)
        (append (list-tail lst (add1 p)) (take lst p)))
      (let* ((len (length prisoners))
             (pos (modulo (- k 1) len)))
        (if (= len 1)
            (display prisoners)
            (begin 
              (display (list-ref prisoners pos))
              (display " ")
              (advanced-f (new-list prisoners pos) k)))))
    复制代码

    运行示例:

    > (advanced-f   '(1 2 3 4 5)   3)
    3 1 5 2 (4)

    同样用的scheme,同样只用了简短的几行代码就解决了问题。至于采用了什么方法,我只简单说几句就不再详细描述了。

    advanced-f 函数每次只杀掉一名囚犯并打印出来,然后以这名囚犯为界将囚犯列表分为头尾两部分,头部接到尾部上生成新的囚犯列表。将新列表带入下一次操作。直到列表只剩一个人。

    结束。

    如果程序有什么错误,请大家不吝指出,我也及时更正。

     
     
    分类: 小算法

    分享 - Hybrid 开发将博客园集成到自己的网站中 - 效果高大上 :)

     

    其实问题很简单: 我的产品页面在 http://www.gdtsearch.com/products.spiderstudio.docapi.htm, 这是一个静态页面; 而我所有的技术博客都在博客园中. 为了让访问者能够直接在产品页面中看到我最新的技术博客, 我将博客页面用IFrame嵌入到了产品页面中:

    这效果简直是,,, 矮矬穷, 如何叫人能够忍受? 于是乎一个改造工程开始了, 基本思路简单清晰:

    1. 用SS编写采集脚本, 并编译成DLL

    2. 用NodeJS编写一个WebApi, 其中调用上面的DLL来获取数据, 然后提供JSONP的结果集

    3. 在产品页面中用jquery.Ajax来异步加载数据

    开始实施:

    首先打开SS编写采集脚本: (http://www.gdtsearch.com/products.spiderstudio.docapi.htm)

     View Code

    然后生成DLL:

    之后再编写NodeJS脚本提供WebApi:

    NodeJS调用.NET的DLL需要用到Edge.js (http://tjanczuk.github.io/edge/#/)

    然后我还用到了Express.js来简化脚本 (http://expressjs.com/)

    先编写一个DLL功能的代理脚本 proxy.js

     View Code

    再写WebApi:

     View Code

    测试一下, 一切正常!

    将Node脚本部署到服务器上运行起来: http://wsoa-mini.cloudapp.net:31337/?callback=test

    最后在前端用JQuery.Ajax取数据, 呈现:

    HTML

     View Code

    CSS

     View Code

    Javascript, 除了呈现, 还提供了排序, 搜索功能 :)

     View Code

    okay, 大功告成!

    再次打开页面: http://www.gdtsearch.com/products.spiderstudio.docapi.htm

    有没有几分惊艳的赶脚? 呵呵, 反正我认为终于有点高大上了:)

    到此我的目的终于达到了, 今后只要在园子里面发文, 就会自动同步到产品页面中, 妥妥的!

    本例中用到的工具:

    SS - http://www.gdtsearch.com/products.spiderstudio.docapi.htm

    NodeJS - http://nodejs.org/

    Edge.js - http://tjanczuk.github.io/edge/#/

    Express.js - http://expressjs.com/

    另需服务器一台host WebApi. 

    怎么样, 不错吧? 你也动手试试吧!

     
     
    分类: Spider Studio
  • 相关阅读:
    样式
    样式表的类别、选择器和优先级
    随记
    框架
    表单元素
    HTLM内容容器标签和常用标签
    HTML5的意义、改变以及全局属性
    11月21日html基础
    感想 目标和展望
    C++结构体实例和类实例的初始化
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3516703.html
Copyright © 2011-2022 走看看