【刷题记录】 UVA11214 Guarding the Chessboard

本文介绍了一种使用迭代加深搜索和回溯解决在n*m棋盘上放置最少数量的皇后以保护所有‘X’型区域的问题。通过标记方向状态而非坐标状态,有效减少计算时间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一. 问题描述

二. 题解代码


一. 问题描述

给出n*m的棋盘,上面被标记‘X’的地方需要放置皇后来保护,问最少需要几个皇后能保护所有的‘X’型区域。注意:(1)皇后可以放置在任何'.'或者‘X’上 (2)皇后保护自己所在的这一列,这一行,左右斜对角线方向上的所有格子

二. 题解代码

        因为深度不确定,放置不确定,直接搜素数据量太大,所以这里采用迭代加深搜索+回溯的方法,限定每次搜索的深度从而限定时间,防止盲目搜索带来的时间浪费,而且这里限制的深度就是放置皇后的个数。

        因为这里每放置一个皇后,就能保护自己这一行,这一列,这两斜的对角线方向。所以我们这里以标记方向状态为标记数组。打破了传统的标记坐标状态从而大大减少了时间。使用vis[4][maxn]来标记方向行,方向列,方向左斜,方向右斜。

(1)vis[0][i]标记i行被保护。

(2)vis[1][j]标记j列被保护。

(3)vis[2][i+j]标记(i,j)左斜对角线方向被标记(这一对角线上x+y全为i+j)。

(4)vis[3][maxn+i-j]标记右斜对角线方向被标记(这一对角线上x-y全为i-j但会出现负数,所以加上maxn变为正数)。

        在搜索到达maxed层后,‘X’全部被保护的条件是,每个'X'至少有一个方向vis被标记也就是被保护。其实现代码如下:

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<bits/stdc++.h>
using namespace std;
const int maxn = 11;
int n,m,maxed;
int maps[10][10];
bool vis[4][2*maxn];
bool judge(){//判断‘X'四个方向是否都被保护
    for(int i = 0;i<n;i++){
        for(int j = 0;j<m;j++){
            if(maps[i][j]&&!vis[0][i]&&!vis[1][j]&&!vis[2][i+j]&&!vis[3][maxn+i-j])return false;
        }
    }
    return true;
}
bool dfs(int i,int dep)
{
    if(dep==maxed){
        if(judge())return true;//如果每个都被保护则结束
        return false;
    }
    for(;i<n;i++){//因为每一行最多放一个皇后就够了,下一个放的皇后一定在上一个皇后的后面行 
        for(int j = 0;j<m;j++){
            bool t1 = vis[0][i],t2 = vis[1][j],t3 = vis[2][i+j],t4 = vis[3][maxn + i - j];//记录原来状态
            vis[0][i] = vis[1][j] = vis[2][i+j] = vis[3][maxn + i - j] = true;//保护四个方向
            if(dfs(i+1,dep+1))return true;
            vis[0][i] = t1,vis[1][j] = t2,vis[2][i+j] = t3,vis[3][maxn + i - j] = t4;//回溯
        }
    }
    return false;
}
int solve()
{
    for(maxed = 0;;maxed++){
        memset(vis,0,sizeof(vis));//vis记录方向
        if(dfs(0,0))return maxed;
    }
    return -1;
}
int main()
{
    int t = 0;
    while(scanf("%d",&n)!=EOF&&n){
        scanf("%d",&m);
        memset(maps,0,sizeof(maps));
        t++;
        for(int i = 0;i<n;i++){
            getchar();//防回车
            for(int j = 0;j<m;j++){
                char ch;
                scanf("%c",&ch);
                if(ch=='X')maps[i][j] = 1;
            }
        }
        int ans = solve();
        printf("Case %d: %d\n",t,ans);
    }
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿阿阿安

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值