蓝桥杯 试题 算法训练 车的放置 C++ 详解

问题描述:

  在一个n*n的棋盘中,每个格子中至多放置一个车,且要保证任何两个车都不能相互攻击,有多少中放法(车与车之间是没有差别的)

输入格式:

  包含一个正整数n

输出格式:

  一个整数,表示放置车的方法数

样例输入:

2

样例输出:

7

数据规模和约定:

  n<=8
  【样例解释】一个车都不放为1种,放置一个车有4种,放置2个车有2种。


前言:

对于这种题,相信对各位 读者/同学 来说已经是比较熟悉套路了吧。

举一反三嘛,类比之前的《无聊的逗》,典型的DFS思想进行枚举。

顺便在CSDN中查了一下,发现都差不多(主要就是dfs解决嘛)

不过倒有迭代解决的:蓝桥杯试题 算法训练 车的放置_梁某人123145的博客-CSDN博客

值得学习,多多益善吧。接下来讲一讲我的思路:


开始 - 上:

刚开始我是这样想的(找规律)

n = 1 , 结果:2 【正确】

n = 2 , 结果:7 = 1(一个都不放) + 4(只放一个) + 2 * 1(放两个) 【正确】

n = 3 , 结果:24 = 1(同上) + 9(同上) + 4 * 2(将3*3分为不同的4个2*2) + 3 * 2(放三个)【错误】

当时还没觉得出错,以为找到了规律: 

【错误】种数 = 1(一个都不放) + n*n(只放一个) + (n-1)^2 * (n-1)(的结果)(放n-1个) + n!(放n个)

说人话:结果等于 一个都不放 + 只放一个 + 在(n-1)*(n-1)中只放(n-1)个 + 在n*n中放n个

但后来发现遗漏了一些情况:在n*n里放n-1个,在n*n里放n-2个,……所以就放弃了。

如果继续完善下去估计会是上面提到的迭代的方法解决。

然后我就放弃找规律,直接枚举算了~~~


开始 - 下:

遍历n*n的方格,对每个(可放的)格子都进行操作(放或不放)。

由于在CSDN上有类似的dfs解法,大同小异,我只提一下我所认为的重点(或区别)

第一、我DFS的第一个操作是:不选,然后才是

区别:对于下一格的选择,我是直接是右一格或换一行的第一个格不是该格的右下一格或左下一格

蓝桥杯 试题 算法训练 车的放置 C++ 详解_第1张图片

第二、参数方面我是只提供第几个格子,不是横纵坐标。(具体看代码:巧用运算赋 / % )

第三、稍微提一下,我的数组是 ii[8][8],下标从0开始,为了配合上一条(以往我是习惯从1开始)

总的来说就只有这些值得稍微注意一下,自行理解 吧~~~


附上代码:

#include
using namespace std;

int xy[8][8] = { 0 };

int n = 0;

int MaxSum = 0;

//检查该位置是否能放车
bool find(int z)
{
	if (0 > z || z > n * n - 1)
	{
		return false;
	}

	int x = z / n; 
	int y = z % n;

	for (int i = 0; i < n; i++)
	{
		if (i != y && xy[x][i] == 1 ||	//同行不同列
			i != x && xy[i][y] == 1)	//同列不同行
		{
			return false;
		}
	}
	return true;
}

//打印 n~n 数组内容
void print()
{
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			cout << xy[i][j] << " ";
		}
		cout << endl;
	}
	cout << endl;
	return;
}

void func(int z = 0)
{
	if (z > n * n - 1)
	{
		MaxSum++;
		//打开此处:(打印)检查各种情况
		//print();
		return;
	}
	//不放
	func(z + 1);

	if (find(z))
	{
		//放
		xy[z / n][z % n] = 1;
		func(z + 1);

		//回溯
		xy[z / n][z % n] = 0;
	}
}

int main()
{
	cin >> n;

	func();

	cout << MaxSum;

	return 0;
}

结束:

…………

你可能感兴趣的:(蓝桥杯,试题,算法训练,蓝桥杯,算法,c++)