2n皇后问题,用c实现

  • //给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。
    //输入格式
    //输入的第一行为一个整数n,表示棋盘的大小。
    //接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。
    //输出格式
    //输出一个整数,表示总共有多少种放法。
    //样例输入
    //4
    //1 1 1 1
    //1 1 1 1
    //1 1 1 1
    //1 1 1 1
    //样例输出
    //2
    //样例输入
    //4
    //1 0 1 1
    //1 1 1 1
    //1 1 1 1
    //1 1 1 1
    //样例输出
    //0
解题思路

a表示棋盘,b[j],c[j]分别表示黑棋,白棋在第j行放的位置;
我的做法是从上往下依次放,行数用m控制;只要最后一行能放就有一种方法,即m == n时,return 1;
先放白棋 i,遇0跳过,在依次判断对角线 列,(因为从上往下放置,不需要判断行是否一样,一行只能放一个;)
列不用多说 只需要b[j]!=i,即不能和上面的在一列;
对角线的话 用斜率±1来判断;(b[j]-i)/(j-m) !=±1;(帮助理解,i是要赋给b[m]的,即(b[j]-b[m])/(j-m);(fx1-fx2)/(x1-x2)表示斜率);如果i成立,就b[m] = i(m行的黑棋在第i列);
再放黑棋 k和白棋同样的步骤,不过黑棋要多判断在本行黑棋的位置,因为黑棋总不能放在白棋上面吧(哈哈哈);即k!=i;
一行放完后直接递归m+1下一行;直到 m==n时完成一次;

实现代码

#include<stdio.h>
#include<windows.h>
#include<malloc.h>
#define N 8
#define M N*N
#pragma warning(disable:4996)

int GoPlay(int* a, int* b, int* c, int m, int n)
{
	if (n < 4)
		return 0;

	if (m == n)
		return 1;

	int i, j, k, count = 0;
	for (i = 0; i < n; i++)
	{
		//白棋先放;
		if (a[m*n + i] == 0)
			continue;
		for (j = 0; j < m; j++)
		{
			if (b[j] == i || b[j] - i == j - m || b[j] + j == i + m)//判断i位置是否可以放置棋子;(斜率判断对角线,+-1)
				break;
		}
		if (j == m)
		{
			b[m] = i;
			//开始放黑棋;
			for (k = 0; k < n; k++)
			{
				if (a[m*n + k] == 0 || k == i)  //判断k位置是否可以放置黑棋,不能和白棋重合;
					continue;
				for (j = 0; j < m; j++)
				{
					if (c[j] == k || c[j] - k == j - m || c[j] + j == k + m)
						break;
				}
				if (j == m)
				{
					c[m] = k;
					count += GoPlay(a, b, c, m + 1, n);
				}

			}
		}
	}
	return count;
}

int main()
{
	int a[M],b[N],c[N], i, j, n;
	scanf("%d", &n);
	for (i = 0; i < n; i++)
	for (j = 0; j < n; j++)
		scanf("%d", &a[i * n + j]);
	printf("%d\n", GoPlay(a, b, c, 0, n));
	system("pause");
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值