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
  • 相关阅读:
    HDU 5744
    HDU 5815
    POJ 1269
    HDU 5742
    HDU 4609
    fzu 1150 Farmer Bill's Problem
    fzu 1002 HangOver
    fzu 1001 Duplicate Pair
    fzu 1150 Farmer Bill's Problem
    fzu 1182 Argus 优先队列
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3516703.html
Copyright © 2011-2022 走看看