• 【算法】算法的应用(三)


    八皇后问题

       求八皇后问题所有的解。
      实例解析:
      这是一个非常古老的问题:如何在一个8*8的棋盘上无冲突地放置8个皇后棋子,称为八皇后问题。
       在国际象棋中,皇后可以沿着任何直线和任何45°斜线移动吃掉别的棋子,因此,任何一个皇后所在的横线上、竖线上和两条对角线上都不能有其他皇后存在。一个完整的、无冲突的八皇后分布称为八皇后问题的一个解。本例求解八皇后的所有解。
      很显然,棋盘的每一行都必须有且只能有一个皇后,因此我们从第一行开始,先放下一个皇后(有8个位置可以放置),然后用递归的方式调用函数本身,去放置后面的棋子,直到第八行放完,则表示找到了一个解。
      对于每一行,可以放置皇后的位置有8个,可用循环的方式来逐个试探,若无冲突,则放置棋子,继续下一层递归调用......,若冲突,则换本行另一个位置。
      下面为程序代码:
    #include <math.h>
    #include <stdio.h>
    #define  MAX  8         //棋盘大小MAX*MAX
    int board[MAX];   
    int count = 0;
    void show_result()          //输出结果
    {
        int i;
        for(i = 0; i < MAX; i++)
            printf("(%d,%d),", i+1, board[i]+1);  //生活中从1开始计数
        printf("
    ");
    }
      
    int check_cross(int n)     //检查是否与前面已经存在的皇后冲突
    {
        int i;
        for(i = 0; i < n; i++)
            if(board[i]==board[n]||(n-i)==abs(board[i]-board[n]))
            return 1;              //若冲突返回1
        return 0;
    }
    void put_chess(int n)          // 在第n行放棋子
    {
        int i;
        for(i = 0; i < MAX; i++)
        {   //依次对第0~7列试探有无冲突
            board[n] = i;                // board[n]存储列号 (行号是n)
            if(!check_cross(n))
            {       //不冲突
                if(n == MAX-1)
                {         //若已经到第八行,则找到一个解
                    count++;
                    printf(“%3d: ”, count);  //输出一个解的序号
                    show_result();            //输出結果
                    if(count%24 == 0)
                    {       //每24行一屏暂停
                        getch();
                        clrscr();
                    }
                }
            else
                put_chess(n+1);   //若未到第八行,则递归调用,进入下一行
            }
        }
    }
      
    int main()
    {
        clrscr();
        puts("The possible placements are:");
        put_chess(0);
        puts("
     Press any key to quit...");
        getch();
        return 0;
    }
      上面使用的是递归算法,还可以使用一种非递归回溯的算法
    #define TRUE  1
    #define FALSE 0
    int nQueens_nonrecursive(int *a, int n)
    {
        int top, i, j, conflict;
        if(n <= 0)
            return FALSE;
        top = -1;
        i = 0;
        do
        {
            conflict = FALSE;
            /*判断会不会与前面已经放置的发生冲突*/
            for(j = 0; j < top+1; j++)
                if(i==a[j]||top+1-j==i-a[j]||top+1-j==a[j]-i)
                    conflict = TRUE;
            if(conflict == FALSE)
            {  //如果不冲突
                a[++top] = i;          //把当前皇后放到第i列
                if(top == n-1)
                           return TRUE;        //问题已成功解决
                i = 0;                  //从下一行的第0列开始,继续试探
            }
            else
            {                      //如果冲突
                while(i == n-1 && top >= 0)
                           i = a[top--];
                i++;
            }
        }
        while(i < n);
        return FALSE;
    }
       这里只列出了部分函数
     
     

    迷宫问题
       从迷宫中找出从入口到出口的所有通道。
     
      实例解析:
      迷宫可用图17-6所示的方块来表示,每个方块或为通道(以空白方块表示)或为墙(以带阴影的方块表示)。要求找到一条从入口到出口的简单路径,即在求得的路径上不能重复出现同一通道块。
      求解迷宫问题的简单方法是:从入口出发,沿某一方向进行搜索,若能走通,则继续向前走;否则沿原路返回,换一方向再进行搜索,直到所有可能的通路都搜索到为止。
      在计算机中可用图17-7所示的二维数组maze[m][n]来表示,数组中元素为0表示通道,为1表示墙。对其中的任一点maze[i][j],可能的运动方向有4个。回溯法求迷宫问题解的过程要用一个栈来保存搜索的路径。
     
      核心代码如下:
    #include <stdio.h>
    #include <stdlib.h>
    #define M 8         // maze数组的行数
    #define N 11        // maze数组的列数
    typedef struct
    {
        int x,y,d;
    }DataType;
    struct  SeqStack
    {  //顺序栈类型定义
        int MAXNUM;
        int  t;         // t<MAXNUM,指示栈顶位置,而不是元素个数
        DataType  *s;
    };
              
    typedef  struct SeqStack  *PSeqStack; //顺序栈类型的指针类型
    PSeqStack CreateEmptyStack_seq(int  n);
    void  push_seq( PSeqStack pastack, DataType x );
    void  pop_seq( PSeqStack pastack );
    int isEmptyStack_seq(PSeqStack pastack);
    DataType  top_seq( PSeqStack pastack );
    /*下面函数求从入口maze[x1][y1]到出口maze[x2][y2]的一条路径,其中 1<=x1, x2<=M-2 , 1<=y1, y2<=N-2 */
    void mazePath(int** maze, int direction[4][2],int x1,int y1,int x2,int y2,int m,int n)
    {
        int i,j,k;
        int g,h;
        PSeqStack  st;
        DataType element;
        st = CreateEmptyStack_seq(m*n);
            if(st == NULL)
                return;
        maze[x1][y1] = 2;         //从入口开始进入, 作标记
        element.x = x1;
        element.y = y1;
        element.d = -1;
        push_seq(st,element);              //入口点进栈
        while(!isEmptyStack_seq(st))
        {    //走不通时, 一步步回退
            element = top_seq(st);
            pop_seq(st);
            i = element.x;
            j = element.y;
            k = element.d + 1;
            while(k <= 3)
            {                   //依次试探每个方向
                g = i + direction[k][0];
                h = j + direction[k][1];
                if(g==x2 && h==y2 && maze[g][h]==0)
                { //走到出口点
                    printf("The revers path is:
    ");  //打印路径上的每一点
                    printf("the node is: %d %d 
    ",g,h);
                    printf("the node is: %d %d 
    ",i,j);
                    while(!isEmptyStack_seq(st))
                    {
                        element = top_seq(st);
                        pop_seq(st);
                        printf("the node is: %d %d 
    ",element.x,element.y);
                    }
                    free(st->s);
                    free(st);
                    return;
                }
                if(maze[g][h] == 0)
                {   //走到没走过的点
                    maze[g][h] = 2;     //作标记
                    element.x = i;
                    element.y = j;
                    element.d = k;
                    push_seq(st,element);  //进栈
                    i = g;     //下一点转换成当前点
                    j = h;
                    k = -1;
                }
                k = k + 1;
            }
        }
        printf("The path has not been found.
    ");
            free(st->s);
        free(st);
    }
      
    int main()
    {
        int maze[M][N] ={
                        {1,1,1,1,1,1,1,1,1,1,1},
                        {1,0,1,0,0,1,1,1,0,0,1},
                        {1,0,0,0,0,0,1,0,0,1,1},
                        {1,0,1,1,1,0,0,0,1,1,1},
                        {1,0,0,0,1,0,1,1,0,1,1},
                        {1,1,0,0,1,0,1,1,0,0,1},
                        {1,1,1,0,0,0,0,0,0,0,1},
                        {1,1,1,1,1,1,1,1,1,1,1},
                        };
        int direction[4][2] = {{0,1},{1,0},{0,-1},{-1,0}};
        mazePath(maze,direction,1,1,6,9,M,N);
        return 0;
    }
     
     

    表达式计算
       对于键盘输入的表达式,判断是否合法,如果合法,输出运算结果。
      说明:
       (1)表达式不能为空
       (2)可以出现在表达式中的字符有:
       运算符“+”、“-”、“*”、“”;
       左右括号“(”、“)”;
       整数(可以是多位的);
       空格和制表符。
      例如:若输入的表达式为“20 + (3*(4+1) - 5)/2 - 3”,则应输出22。
       实例解析:
       使用栈先将中缀表达式转化为后缀表达式,再来求后缀表达式的值。
       1、转化为后缀表达式步骤如下:
    建一个空栈作为运算符栈,顺序扫描中缀表达式。
      ①若读到其他字符:忽略。其他字符包括‘  ’、 ‘ ’等。
       ②若读到数字:输出(指:写入数组)
       ③若读到左括号:入栈
       ④若读到右括号:不断将栈中元素弹出、输出,直到遇到左括号,将其弹出但不输出。
        ⑤若读到加或减:反复检查,若栈不空且栈顶为加、减、乘或除时,弹出并输出栈顶元素。读入的运算符(加或减)入栈。
       ⑥若读到乘或除:若栈不空且栈顶为乘或除时,弹出并输出栈顶元素。读入的运算符(乘或除)入栈
    缀表达式扫描完毕后,将栈中剩余元素弹出、输出。
       2、计算后缀表达式值步骤如下:
       创建一个空栈,顺序扫描后缀表达式
       ①若读到数字:入栈。
       ②若读到其他字符:忽略。其他字符包括‘  ’、 ‘ ’等。
       ③若读到运算符:从栈中弹出两个元素进行计算,将结果入栈。
       后缀表达式扫描完毕后,栈顶元素即为结果。
       程序如下:
    #include <stdio.h>
    #include <malloc.h>
    #define DataType char
    #define TRUE  1
    #define FALSE 0
    #define MAX_SEQSTACK 100
    struct  SeqStack
     {    //顺序栈类型定义
        int MAXNUM;
        int  t;           // t<MAXNUM,指示栈顶位置,而不是元素个数
        DataType  *s;
    };
          
    typedef  struct SeqStack  *PSeqStack; //顺序栈类型的指针类型
    /以下5个函数的实现见本章实例13
    PSeqStack CreateEmptyStack_seq();
    void  push_seq(PSeqStack pastack, DataType x);
    void  pop_seq(PSeqStack pastack);
    int isEmptyStack_seq(PSeqStack pastack);
    DataType  top_seq(PSeqStack pastack);
    //下面代码将中缀表达式转换为后缀表达式,如成功返回TRUE
    int infixtoSuffix(char *infix, char *suffix)
    {
        int state_int = FALSE;
        /*记录状态,TRUE表示刚读入的是数字,FALSE表示刚读入的不是数字。  设置这个变量的目的是每输出一个整数后输出一个空格,以免连续输出的两个整数混在一起。*/
        char c, c2;
        int i, j = 0;
        PSeqStack ps = CreateEmptyStack_seq();
           if(ps == NULL)
                 return FALSE;       
        if(infix[0] == '')
        {
            free(ps->s);
            free(ps);
            return FALSE;
        }
        for(i = 0; infix[i] != ''; i++)
        {
            c = infix[i];
            switch(c){
            case ' ':
                case '	':
                case '
    ':
                    if(state_int == TRUE) //从TRUE到FALSE时,输出空格
                        suffix[j++] = ' ';
                    state_int = FALSE;
                break;
            case '0':
                case '1':
                case '2':
                case '3':
                case '4':
            case '5':
                case '6':
                case '7':
                case '8':
                case '9':
                    state_int = TRUE;
                    suffix[j++] = c;      //遇到数字,输出
                break;
            case '(':
                if(state_int == TRUE)
                    suffix[j++] = ' ';
                state_int = FALSE;
                push_seq(ps, c);
                break;
            case ')':
                if(state_int == TRUE)
                    suffix[j++] = ' ';
                state_int = FALSE;
                c2 = ')';
                while(!isEmptyStack_seq(ps))
                {
                    c2 = top_seq(ps);
                    pop_seq(ps);
                    if(c2 == '(')
                        break;
                    suffix[j++] = c2;
                }   //读入右括号,弹出输出,直到遇到左括号,弹出不输出
                if(c2 != '(')
                {
                    free(ps->s);
                    free(ps);
                    suffix[j++] = '';
                    return FALSE;  //找不到左括号,非法
                }
                break;
            case '+':
                case '-':
                if(state_int == TRUE)
                    suffix[j++] = ' ';
                state_int = FALSE;
                while(!isEmptyStack_seq(ps))
                {
                    c2 = top_seq(ps);
                    if(c2=='+' || c2=='-' || c2=='*' || c2=='/')
                    {
                        pop_seq(ps);
                        suffix[j++] = c2;
                    }        //栈顶为加减乘除时,弹出栈顶元素并输出
                    else
                        break;
                }
                push_seq(ps,c);
                break;
            case '*':
                case '/':
                if(state_int == TRUE)
                    suffix[j++] = ' ';
                state_int = FALSE;
                while(!isEmptyStack_seq(ps))
                {
                    c2 = top_seq(ps);
                    if(c2 == '*' || c2 == '/' )
                    {
                        pop_seq(ps);
                        suffix[j++] = c2;
                    }   //栈顶为加减乘除时,弹出栈顶元素并输出
                    else
                        break;
                }
                push_seq(ps,c);
                break;
            default:             //出现其他非法字符
                free(ps->s);
                free(ps);
                suffix[j++] = '';
                return FALSE;
            }
        }
        if(state_int == TRUE)
            suffix[j++] = ' ';
        while(!isEmptyStack_seq(ps))
        {
            c2 = top_seq(ps);
            pop_seq(ps);
            if(c2 == '(')
            {
                free(ps->s);
                free(ps);
                suffix[j++] = '';
                return FALSE;
            }
            suffix[j++] = c2;
        }
        free(ps->s);
           free(ps);
        suffix[j++] = '';
        return TRUE;
    }
    /*下面函数用于计算后缀表达式的值,若非法返回FALSE;否则返回TRUE,且*presult存放计算结果*/
    int calculateSuffix(char *suffix, int *presult)
    {
        int state_int = FALSE;
        int num = 0, num1, num2;
        int i;
        char c;
        PSeqStack ps = CreateEmptyStack_seq();
        if(ps == NULL)
            return FALSE;      
        for(i = 0; suffix[i] != ''; i++)
        {
            c = suffix[i];
            switch(c)
            {
                case '0':
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                case '9':
                if(state_int == TRUE)
                    num = num*10 + c - '0';
                else
                    num = c -'0';
                state_int = TRUE;
                break;
            case ' ':
            case '	':
            case '
    ':
                if(state_int == TRUE)
                {
                    push_seq(ps, num);
                    state_int = FALSE;
                }
                break;
            case '+':
            case '-':
            case '*':
            case '/':
                if(state_int == TRUE)
                {
                    push_seq(ps, num);
                    state_int = FALSE;
                }
                if(isEmptyStack_seq(ps))
                {
                    free(ps->s);
                    free(ps);
                    return FALSE;
                }
                num2 = top_seq(ps);
                pop_seq(ps);
                if(isEmptyStack_seq(ps))
                {
                    free(ps->s);
                    free(ps);
                    return FALSE;
                }
                num1 = top_seq(ps);
                pop_seq(ps);
                if(c == '+')
                    push_seq(ps, num1+num2);
                if(c == '-')
                    push_seq(ps, num1-num2);
                if(c == '*')
                    push_seq(ps, num1*num2);
                if(c == '/')
                {
                    if(num2 == 0)
                    {    //除数为0返回FALSE
                        free(ps->s);
                        free(ps);
                        return FALSE;
                    }
                    push_seq(ps, num1/num2);
                }
                break;
            default:              //出现其他非法字符
                free(ps->s);
                    free(ps);
                return FALSE;
            }
        }
        *presult = top_seq(ps);
        pop_seq(ps);
        if(!isEmptyStack_seq(ps))   //栈中还有其他字符,非法
        {
            free(ps->s);
            free(ps);
            return FALSE;
        }
        free(ps->s);
            free(ps);
            return TRUE;
    }
      
    int main()
    {
        char infix[80] = "20+(3*(4+1)-5)/2-3";
        char suffix[80];
        int result;
        if(infixtoSuffix(infix,suffix) == TRUE)
        {
            if(calculateSuffix(suffix,&result) == TRUE)
                printf("The Reuslt is: %3d
    ", result);
            else
                printf("Error!
    ");
        }
        else
            printf("Input Error!
    ");
        return 0;
    }
     
     
     

    本文出自 “成鹏致远” 博客,请务必保留此出处http://infohacker.blog.51cto.com/6751239/1171355

  • 相关阅读:
    [整理]修改git 默认编辑器为vim
    [转]如何清空Chrome缓存和Cookie
    [整理]docker内部时区修改的两种方法
    [译]10个有关SCP的命令
    [译]在python中如何有效的比较两个无序的列表是否包含完全同样的元素(不是set)?
    通过设计表快速了解sql语句中字段的含义
    [整理]什么是排序算法的稳定性,为什么它很重要?
    pyinstaller打包自己的python程序
    [问题解决]ps aux中command命令相同,如何找出自己要的进程号?
    [常识]Windows系统里休眠和睡眠的区别?
  • 原文地址:https://www.cnblogs.com/lcw/p/3159445.html
Copyright © 2020-2023  润新知