Uva11214 Guarding the Chessboard【dfs回溯】【习题7-10】

题目:Guarding the Chessboard

题意:一个n*m的矩阵上有一堆敌人X,最少放置几个皇后可全部消灭。

思路:

(1)枚举:枚举矩阵中的每一个位置,用当前index/m 和 index%m 得出 横纵坐标。

(2)标记:同八皇后问题一样,也是标记行,列,对角线。但这个标记不是用于当前是否此点放没放皇后,而是用于检测敌人是否被消灭了。而且,这里没枚举到一个位置时,先将此位置的标记预先继续下来,然后再标记。最后再还原。还原的时候不是直接赋值0,因为有可能不一样,所以要预先记录下来。

(3)判断:遍历整个矩阵中的X位置,看X位置的标记数组是否都标记了,如果都标记了说明皇后都攻击到了,否则没有。

(4)迭代皇后数量,一旦成功,即为最少!

思维一定要开阔,我开始想的是每次看消灭了的敌人数。其实就是利用八皇后的标记,看敌人是否在标记范围内就判断了!!!还有就是标记不是都永远是一个套路  ,本题就是标记数组有变化,需要预先保存后还原!

参考:专攻挖掘机炒鸡蛋算法博客

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 15;
char g[maxn][maxn];
int visit[4][maxn*3];
int n,m,cnt,maxd;
inline bool success(){//寻找每个X障碍物所对应的行,列和对角线是否被标记过
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            if(g[i][j] == 'X' && !visit[0][i] && !visit[1][j] && !visit[2][i+j] && !visit[3][i-j+maxn]) return false;
    return true;
}
bool dfs(int index,int d){
    if(success()) return true;
    if(d == maxd) return false;
    for(int pos=index;pos < n*m;pos++){//枚举横纵坐标
        int i = pos/m , j = pos%m,save[4];//注意save不能设置全局
        save[0] = visit[0][i];save[1] = visit[1][j];save[2] = visit[2][i+j];save[3] = visit[3][i-j+maxn];//将此点之前的标记记录
        visit[0][i] = visit[1][j] = visit[2][i+j] = visit[3][i-j+maxn] = 1;//标记此点
        if(dfs(pos,d+1)) return true;
        visit[0][i] = save[0];visit[1][j] = save[1];visit[2][i+j] = save[2];visit[3][i-j+maxn] = save[3];//还原
    }
    return false;
}
inline int solve(){//枚举深度即最少皇后
    for(maxd=0;maxd<6;maxd++){
        memset(visit,0,sizeof(visit));
        if(dfs(0,0)) return maxd;
    }
    return 5;//最大为5
}
int main()
{
    int kcase = 1;
    while(scanf("%d",&n)!=EOF && n){
        scanf("%d",&m);
        for(int i=0;i<n;i++) scanf("%s",g[i]);
        printf("Case %d: %d\n",kcase++,solve());
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值