蓝桥杯 车的放置 C++

文章讨论了一个在n*n棋盘上放置车的问题,要求任何两个车不能相互攻击。这个问题类似于N皇后问题,但车的数量可以小于棋盘的大小。解决策略是通过循环车的数量并使用回溯法来寻找所有可能的放置方式。对于每种车的数量,计算组合数并乘以回溯法得到的结果,最后得出总的放置方法数。
摘要由CSDN通过智能技术生成
问题描述

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

输入格式

包含一个正整数n

输出格式

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

样例输入

2

样例输出

7

数据规模和约定

n<=8
  【样例解释】一个车都不放为1种,放置一个车有4种,放置2个车有2种。
首先在这里需要先补充一下题目意思,题目对于不能相互攻击没有一个准确的定义,这里我们参考N皇后问题,N皇后问题要求2个皇后不能放在同一行或者同一列或者同意斜线上。根据样例解释,当棋盘大小为2时,放置两个车有两种,我们可以推测题目应该是要求两个车不能放在同一行或者同一列。

明确题意之后,我们开始解题。乍一眼看到这个问题,学过算法的小伙伴肯定很熟悉,这和我们的N皇后问题简直如出一辙(恭喜你,迈出了最关键的一步),但仔细一看,发现这题目有点别的东西哟!

N后问题使用的是回溯法,这道题其实只是在回溯法外面再套一层循环而已,为什么这么说呢?
N后问题,皇后的数量和棋盘的大小是一样的,每个皇后占一列,因此行索引是固定的,解空间(x1,x2…xn)的取值是列索引。而对该问题来说,由于车的数量小于等于棋盘大小,当车数量小于棋盘大小时,小车占的行是一个组合数。到这里,问题似乎变得明了了些。我们只需要对小车数量从0~n循环,确定小车数量后,利用回溯法,对列搜索(和N后问题一样),讲列搜索结果和组合数相乘即可。举个例子,当棋盘大小为3,小车数量为2时,可以选择的行的情况是 C 3 2 C_{3}^{2} C32(1、2行;1、3行、2、3行)。回溯法对列搜索如图所示
在这里插入图片描述

代码
#include <iostream>

using namespace std;

static int* x;//解空间
static int sum=0;
static int n;
//约束条件,列的约束
bool yueshu(int t) //当前x0-xt-1都已经确定了列
{
    for(int i=0; i<t; i++)
    {
        if(x[t]==x[i]) return false;
    }
    return true;
}

//回溯法得到每个xi的值
void backtrack(int t,int num)
{
//    x[i]的取值是0~n-1
    if(t==num) //产生一种新方案
    {
        sum++;
    }
    else
    {
        for(int i=0; i<n; i++)//可以选择棋盘中的任意一列,因此为n
        {
            x[t]=i;
            if(yueshu(t)){
                backtrack(t+1,num);
            }
        }
    }
    return;
}
int jiechen(int n){
    int r=1;
    for(int i=1;i<=n;i++){
        r=r*i;
    }
    return r;
}
int main()
{
//n*n棋盘格,一个大的循环,确定放的小车的数量s,s<n;
//解向量元素xi(i<s)的值代表车i放在哪一列,即i确定了行数,xi确定了列数,得到的小车数量为n时的放置方案数r;
//由于小车的数量s小于等于n,因此r*C n s
    cin >>n;
//    n=2;
    x=new int[n];//由于最多可以放n辆车,因此解向量的大小为n
    int result=0;//方法总数,sum是某一次
    for(int s=0; s<=n; s++)//放1辆车一直到放n辆车
    {
        backtrack(0,s);
        result+=sum*jiechen(n)/(jiechen(s)*jiechen(n-s));
        for(int i=1;i<n;i++){//需要讲解空间数值清除,sum也要重新计数
            x[i]=-1;
        }
        sum=0;
    }
    cout << result;
}

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值