八皇后问题

最近在学C语言,就用C实现了一遍八皇后问题。
用回溯算法实现的(我学算法学的不系统,不确定正统的回溯算法是不是像我这样实现的)。
写程序用了一个小时,调用了一个小时。整理,重命名变量,写注释又用了一个小时。
很多人用递归实现的,在判断皇后是否冲突时需要每次执行一个循环,影响效率。
我引入了三个一维数组来分别标记指定列,左斜线,右斜线是否放置了皇后。在判断皇后是否冲突时只需要利用下标检查这三个数组就行了。
左斜线,右斜线:我自己引入的概念。
左斜线:棋盘的左上第一条斜线坐标为0,一直到右下角一共有2*n-1条左斜线。
右斜线:左下第一条斜线坐标为0,一直到右上一共有2*n-1条右斜线。


#include <stdio.h>
#include <stdlib.h>


void solveNQueens();

/*
 * 获取棋盘中指定位置的右斜线索引
 * 为方便回溯,需要记录斜线上是否放置了一个皇后
 * 对一个指定的n,一共有(n-1)*2 + 1条右斜线
 * 假设左下的斜线坐标为0,其相邻的斜线坐标1,依次加1到最右上的斜线坐标为(n-1)*2
 */
int getRigthDiagonalIndex(int row, int column);

/*
 * 获取棋盘中指定位置的左斜线索引
 */
int getLeftDiagonalIndex(int row, int column);

int resultCount;//结果数

//打印结果
void printResult();

//放置一个皇后
void addAQueen(int row, int column);

//移除一个皇后
void removeAQueen(int row, int column);

//找到一行中下一个可以放皇后的位置
int findNextValidColumn(int row, int currentColumn);

int n;
int * result;//暂存一个结果
char * columnFlag;//标记:列是否放置了棋盘
char * rightDiagonalFlag;//标记:右斜线是否放置了皇后
char * leftDiagonalFlag;//标记:左斜线是否放置了皇后

int main(void)
{

	printf("请输入一个整数\n");
	scanf("%d", &n);

	resultCount = 0;
	solveNQueens();

	return 0;
}

//N皇后问题
void solveNQueens()
{
	int diagonalCount = n * 2 - 1;//斜线个数
	result = (int*) malloc(n * sizeof(int));
	columnFlag = (char*) malloc(n * sizeof(char));
	rightDiagonalFlag = (char*) malloc(diagonalCount * sizeof(char));
	leftDiagonalFlag = (char*) malloc(diagonalCount * sizeof(char));

	int row,column,rightDiagonal,leftDiagonal,i;
	
	//init
	for ( i = 0; i < n; i++)
	{
		columnFlag[i] = '0';
	}
	for ( i = 0; i < diagonalCount; i++)
	{
		rightDiagonalFlag[i] = '0';
		leftDiagonalFlag[i] = '0';
	}

	/*
	 * 回溯算法
	 */
	row = 0;
	result[0] = -1;
	while ( row >= 0 )
	{
		  if ( result[row] >= 0 ) //如果当前行原来放置了一个皇后,先移除
		  {
		  	removeAQueen(row, result[row]);
		  }
		  
		  //找到下一个可以放置皇后的位置
	      column = findNextValidColumn(row, result[row]);
	      
	      if ( column == -1 ) //该行找不到可以放皇后的位置了
	      {
	      		--row;//返回上一行
		  }
		  else
		  {
		  		result[row] = column;//记录皇后位置
		  		addAQueen(row, column);//标记该皇后所在的列和斜线
		  		++row;//到下一行
		  		
		  		if ( row == n )//找到一个解
		  		{
		  			 printResult(result, n);

					 --row;//退回到上一行
		  		}
		  		else//初始化下一行
		  		{
		  			result[row] = -1;
		  		}
		  }
	}

}

void addAQueen(int row, int column)
{
	int rightDiagonal = getRigthDiagonalIndex(row, column);
	int leftDiagonal = getLeftDiagonalIndex(row, column);
	columnFlag[column] = '1';
	rightDiagonalFlag[rightDiagonal] = '1';
	leftDiagonalFlag[leftDiagonal] = '1';

}

int findNextValidColumn(int row, int currentColumn)
{
	 int column;
	 int rightDiagonal;
	 int leftDiagonal;
	 for( column = currentColumn + 1; column < n; column++)
	 {
	 	   	rightDiagonal = getRigthDiagonalIndex(row, column);
			leftDiagonal = getLeftDiagonalIndex(row, column);
			if ( columnFlag[column] == '0' && rightDiagonalFlag[rightDiagonal] == '0'
					  && leftDiagonalFlag[leftDiagonal] == '0' )
			{
				 return column;
			}
	 }
	 return -1;
}
	 	  

void removeAQueen(int row, int column)
{
	columnFlag[column] = '0';
	int rightDiagonal = getRigthDiagonalIndex(row, column);
	rightDiagonalFlag[rightDiagonal] = '0';
	int leftDiagonal = getLeftDiagonalIndex(row, column);
	leftDiagonalFlag[leftDiagonal] = '0';
}

int getRigthDiagonalIndex(int row, int column)
{
	return (n - 1) + column - row;
}

int getLeftDiagonalIndex(int row, int column)
{
	return row + column;
}

void printResult()
{
	printf("第%d个解:\n", ++resultCount);
	int i,j,k;
	for (i = 0; i < n; i++)
	{
		for (j = 0; j < *(result + i); j++)
		{
			printf("%c ", '*');
		}
		
		printf("%c ", 'Q');
		
		for (k = *(result + i) + 1; k < n; k++)
		{
			printf("%c ", '*');
		}
		printf("%c",'\n');
	}
	printf("%c",'\n');
	
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值