八皇后问题
求八皇后问题所有的解。 实例解析: 这是一个非常古老的问题:如何在一个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("\n"); } 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("\n 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:\n"); //打印路径上的每一点 printf("the node is: %d %d \n",g,h); printf("the node is: %d %d \n",i,j); while(!isEmptyStack_seq(st)) { element = top_seq(st); pop_seq(st); printf("the node is: %d %d \n",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.\n"); 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、转化为后缀表达式步骤如下: 建一个空栈作为运算符栈,顺序扫描中缀表达式。 ①若读到其他字符:忽略。其他字符包括‘ ’、 ‘ \t’等。 ②若读到数字:输出(指:写入数组) ③若读到左括号:入栈 ④若读到右括号:不断将栈中元素弹出、输出,直到遇到左括号,将其弹出但不输出。 ⑤若读到加或减:反复检查,若栈不空且栈顶为加、减、乘或除时,弹出并输出栈顶元素。读入的运算符(加或减)入栈。 ⑥若读到乘或除:若栈不空且栈顶为乘或除时,弹出并输出栈顶元素。读入的运算符(乘或除)入栈 缀表达式扫描完毕后,将栈中剩余元素弹出、输出。 2、计算后缀表达式值步骤如下: 创建一个空栈,顺序扫描后缀表达式 ①若读到数字:入栈。 ②若读到其他字符:忽略。其他字符包括‘ ’、 ‘ \t’等。 ③若读到运算符:从栈中弹出两个元素进行计算,将结果入栈。 后缀表达式扫描完毕后,栈顶元素即为结果。 程序如下:
#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] == '\0') { free(ps->s); free(ps); return FALSE; } for(i = 0; infix[i] != '\0'; i++) { c = infix[i]; switch(c){ case ' ': case '\t': case '\n': 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++] = '\0'; 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++] = '\0'; 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++] = '\0'; return FALSE; } suffix[j++] = c2; } free(ps->s); free(ps); suffix[j++] = '\0'; 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] != '\0'; 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 '\t': case '\n': 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\n", result); else printf("Error!\n"); } else printf("Input Error!\n"); return 0; }
本文出自 “成鹏致远” 博客,请务必保留此出处http://infohacker.blog.51cto.com/6751239/1171355