Guarding the Chessboard(UVa 11214)

本题题意:

输入一个n*m的棋盘,某些格子有标记,用最少的皇后占据或者攻击所以带标记的格子。皇后的攻击范围为同行同列和同对角线。

可以使用IDA*算法,即从样例可以发现只需要最多5个棋子就可以对棋盘上所有地方进行攻击,因而使用IDA*进行对应的剪枝即可。

#include<cstdio>
#include<cstring>
using namespace std;

int n,m,kase=0,maxd;
bool vis[4][30];///表示皇后已经攻击的范围,vis[0][]中存储的是行,vis[1][]中存储的是每列,vis[2][]中存储的是每个副对角线,vis[3][]是每个主对角线
char chess[15][15];

bool dfs(int pos,int r)
{
    if(pos==maxd){
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            if(chess[i][j]==‘X‘&&!vis[0][i]&&!vis[1][j]&&!vis[2][i+j]&&!vis[3][i-j+n])///如果达到最大深度,但是仍有X点不处于皇后的攻击范围内,则剪枝
                return false;
        }
        return true;
    }
    for(int i=r;i<=n;i++)///从当前行开始,因为前面的行已经搜索过
    for(int j=1;j<=m;j++){
        if(!vis[0][i]||!vis[1][j]||!vis[2][i+j]||!vis[3][i-j+n]){///若存在有未被攻击的地方,则进行放棋
            bool v1=vis[0][i],v2=vis[1][j],v3=vis[2][i+j],v4=vis[3][i-j+n];
            vis[0][i]=vis[1][j]=vis[2][i+j]=vis[3][i-j+n]=true;
            if(dfs(pos+1,r+1)) return true;///若要放置棋子数最小,则皇后必定会放于是X的位置
            vis[0][i]=v1,vis[1][j]=v2,vis[2][i+j]=v3,vis[3][i-j+n]=v4;///还原
        }
    }
    return false;
}

int main()
{
    while(~scanf("%d%d",&n,&m)&&n)
    {
        for(int i=1;i<=n;i++) scanf("%s",chess[i]+1);
        for(maxd=1;maxd<5;maxd++)
        {
            memset(vis,0,sizeof(vis));
            if(dfs(0,0)) break;
        }
        printf("Case %d: %d\n",++kase,maxd);
    }
    return 0;
}
时间: 2024-10-12 17:04:30

Guarding the Chessboard(UVa 11214)的相关文章

Ant on a Chessboard UVA 10161

说说:首先,最终蚂蚁的行走路线可以看成一直在沿着正方形的边沿走.而最大的正方形的边长是平方之后小于所给时间N的最大整数.这个最大的正方形的边长可以通过二分法获得.而且要注意的是根据边长的奇偶性,剩余路线的出发点可能在右下角,也可能在左上角.然后将剩余的要走的路再分成在到达顶点(即转折点)之前和之后,通过简单的数学计算最后就可以判断出蚂蚁最后的位置啦! 题目:  Ant on a Chessboard Background One day, an ant called Alice came to

UVA 11214 Guarding the Chessboard 守卫棋盘(迭代加深+剪枝)

就是个暴力,和八皇后很像,但是还是要加一些的剪枝的. 1.最裸的暴搜 6.420s,差点超时 2.之前位置放过的就没必要在放了,每次从上一次放的位置开始放 0.400s #include<cstdio> #include<cstring> const int maxn = 11; char G[maxn][maxn]; int maxd; int n,m; bool visi[maxn],visj[maxn],vis1[maxn<<1],vis2[maxn<<

UVA - 11214 Guarding the Chessboard (可重复覆盖,DLX+IDA*)

题目链接 正解是IDA*+四个方向判重,但由于是个裸的可重复覆盖问题,可以用DLX水过~ 每个格子与放上皇后能干掉的标记连边,跑可重复覆盖DLX.注意要用IDA*来优化,否则会超时. 1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=10+2; 5 int n,m,np,ka; 6 char s[N][N]; 7 struct P {int x,y;} p[N*N]; 8

11214 - Guarding the Chessboard(暴力搜索)

IDA*算法, 从小到大枚举深度上限,不过该题是有深度上限的,题目中的第一个样例表明:最多需要5个皇后就可以覆盖整个棋盘 . 利用紫书上的技巧,我们可以快速的判断任意两个棋子是不是在同一行.同一列.同一对角线 (详情见紫书P193那两个图). 这样之后暴力搜索就可以了 . 每一层需要O(nm)的复杂度,但是实际上并不需要那么大的复杂度 .和八皇后问题类似 , 当前行之前的行已经放置了皇后,所以不必在管,每次从下一行开始放置就好 . 细节见代码: #include<bits/stdc++.h>

Guarding the Chessboard

Given an n ∗ m chessboard with some marked squares, your task isto place as few queens as possible to guard (attack or occupy) allmarked squares. Below is a solution to an 8 ∗ 8 board with everysquare marked. Note that queens can be placed on non-mar

UVA-11214 Guarding the Chessboard (迭代加深搜索)

题目大意:在一个国际象棋盘上放置皇后,使得目标全部被占领,求最少的皇后个数. 题目分析:迭代加深搜索,否则超时. 小技巧:用vis[0][r].vis[1][c].vis[2][r+c].vis[c-r+N]分别标志(r,c)位置相对应的行.列.主.副对角线有没有被占领(详见<入门经典(第2版)>P193),其中N表示任意一个比行数和列数都大(大于等于)的数. 代码如下: # include<iostream> # include<cstdio> # include&l

UVa11214 Guarding the Chessboard (IDA*)

链接:http://vjudge.net/problem/23958 分析:控制最大递归深度为maxd,也就是枚举个数maxd个皇后守卫的时候,dfs以行枚举放皇后守卫的位置,确保放皇后守卫的位置的行,列,主和副对角线上没有其它守卫,否则就不是最优的了,每次递归从上次放的行的下一行开始放,放满maxd个后进行判断是否所有标记格子都被攻击到.是则直接返回true输出最少守卫,否则返回递归上一层继续枚举,vis要复位. 1 #include <cstdio> 2 #include <cstr

UVa11214 - Guarding the Chessboard

给出m*n棋盘上的目标点,求最少用几个皇后可以守卫所有目标点. 类似八皇后做法,2维数组标记行.列.主对角线.副对角线. 有个加速的技巧,测试之后发现10*10的棋盘全部守卫至少需要5个,所以上限就是5,当maxd等于5时直接输出,不进行搜索. #include<cstdio> #include<cstring> using namespace std; const int maxn=11; int n,m,t,maxd; bool g[maxn][maxn],vis[4][max

UVA 10620 - A Flea on a Chessboard(鸽笼原理)

UVA 10620 - A Flea on a Chessboard 题目链接 题意:给定一个跳蚤位置和移动方向,现在在一个国际象棋棋盘上,左下角为黑格,一个格子为s*s,判断能否移动到白格子,问要移动多少次才能到白格,边界不算白格. 思路:利用鸽笼原理落在黑格子和边界上的一共有(s + 1)^2个点,也就是说,如果形成循环,周期肯定在这之内,所以可以不断去模拟跳格子,直到踩到白格,或者踩到之前落到过的黑格就结束 不过其实还有更优的方法,因为跳蚤跳跃路径为直线,观察下可以发现如果可以到白格,最多