八皇后问题
求八皇后问题所有的解。
实例解析:
这是一个非常古老的问题:如何在一个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