问题描述:
在一个n*n的棋盘中,每个格子中至多放置一个车,且要保证任何两个车都不能相互攻击,有多少中放法(车与车之间是没有差别的)
输入格式:
包含一个正整数n
输出格式:
一个整数,表示放置车的方法数
样例输入:
2
样例输出:
7
数据规模和约定:
n<=8
【样例解释】一个车都不放为1种,放置一个车有4种,放置2个车有2种。
前言:
对于这种题,相信对各位 读者/同学 来说已经是比较熟悉套路了吧。
举一反三嘛,类比之前的《无聊的逗》,典型的DFS思想进行枚举。
顺便在优快云中查了一下,发现都差不多(主要就是dfs解决嘛)
不过倒有迭代解决的:蓝桥杯试题 算法训练 车的放置_梁某人123145的博客-优快云博客
值得学习,多多益善吧。接下来讲一讲我的思路:
开始 - 上:
刚开始我是这样想的(找规律)
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的方格,对每个(可放的)格子都进行操作(放或不放)。
由于在优快云上有类似的dfs解法,大同小异,我只提一下我所认为的重点(或区别)
第一、我DFS的第一个操作是:不选,然后才是选。
区别:对于下一格的选择,我是直接是右一格或换一行的第一个格,不是该格的右下一格或左下一格。
第二、参数方面我是只提供第几个格子,不是横纵坐标。(具体看代码:巧用运算赋 / % )
第三、稍微提一下,我的数组是 ii[8][8],下标从0开始,为了配合上一条(以往我是习惯从1开始)
总的来说就只有这些值得稍微注意一下,自行理解 吧~~~
附上代码:
#include<iostream>
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;
}
结束:
…………