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

来源:互联网 发布:ubuntu麒麟 编辑:程序博客网 时间:2024/05/02 02:52

题目: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;}


0 0
原创粉丝点击