数据结构学习 棋盘问题

2023-12-15 16:35:20

题目:

问题:在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。

input: 输入含有多组测试数据。 每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n 当为-1 -1时表示输入结束。 随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。

output:对于每一组数据,给出一行输出,输出摆放的方案数目C (数据保证C<2^31)。

这里得用dfs 回溯 剪枝

错误点:

这道题是我在学习dfs里碰到的一道题。这道题我在做的时候,一开始没有关注棋盘的重复问题。导致做错了。具体来讲:

我写了一个这样的for循环:

    for (int i = 0; i < n; ++i)
    {
        for (int j = 0; j < n; ++j)
        {
            if (vis_r[i] == 0 && vis_c[j] == 0)
            {
                vis_r[i] = 1;//标记
                vis_c[j] = 1;
                dfs(step + 1);
                vis_r[i] = 0;//回溯
                vis_c[j] = 0;
            }
        }
    }

我试图遍历棋盘上每个点,并且在确定第一个点之后,在棋盘任意位置继续找下一个摆放的点。在任意位置摆放下一个点的行为将会导致摆放方案的重复。

具体来说,比如有一个3×3的棋盘,想要放3个棋子(n=3,k=3):

1、在i=0,j=0时,机器会找到这样一种情况:【标红的是(0,0)】

1

1

1

?2、但是在i=1,j=1时,机器又会找到这样相同的情况,并计数:【标红的是(1,1)】

1

1

1

?3、紧接着,在i=2,j=2时,机器又会找到这样相同的情况,并计数:【标红的是(2,2)】

1

1

1

?也就是说,因为我没有做合适的剪枝,导致重复计算了,相同的摆放方法被我计数了3次。

改正的方案:

    for (int i = r; i < n; ++i)
    {
        for (int j = 0; j < n; ++j)
        {
            if (vis_r[i] == 0 && vis_c[j] == 0)
            {
                vis_r[i] = 1;//标记
                vis_c[j] = 1;
                dfs(step + 1,r+1);
                vis_r[i] = 0;//回溯
                vis_c[j] = 0;
            }
        }
    }

多加了一个变量r来记录可以被用来遍历的行的范围。限制下一步棋子找的范围。即:

每次都从放过棋子下一行开始搜索,保证不重复。

第一行已经被找过了i=0

循环回到step=1,从第二行(r=1)找

1

此时想要确定ii只能从第三行(r+1)开始找

1

总之找到一个合适的剪枝,别让它重复了。

复杂度:

时间复杂度O(n!)

空间复杂度O(n) 两个vis

代码:

太懒了,直接写在main这了。这样写是不合适的。

#include <iostream>
#include <vector>
//棋盘问题
int n = 3;
int k = 2;
int count = 0;
int step = 1;
std::vector<int> vis_r(n);
std::vector<int> vis_c(n);
void dfs(int step, int r);
int main()
{

    dfs(step, 0);

    std::cout << count;
}
void dfs(int step,int r)
{
    if (step == n + 1)
    {
        ++count;
        return;
    }
    for (int i = r; i < n; ++i)
    {
        for (int j = 0; j < n; ++j)
        {
            if (vis_r[i] == 0 && vis_c[j] == 0)
            {
                vis_r[i] = 1;//标记
                vis_c[j] = 1;
                dfs(step + 1,r+1);
                vis_r[i] = 0;//回溯
                vis_c[j] = 0;
            }
        }
    }
    return;
}

文章来源:https://blog.csdn.net/rainssssss/article/details/135018386
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。