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<<1];

bool dfs(int d,int si,int sj)
{
    if(d == maxd){
        for(int i = 0; i < n; i++)
            for(int j = 0; j < m; j++){
                if(G[i][j] == ‘X‘&&!visi[i]&&!visj[j]&&!vis1[i+j]&&!vis2[i-j+10])
                    return false;
            }
        return true;
    }
      for(int i = si; i < n; i++){
            for(int j = (i == si?sj:0); j < m; j++)
            if(!visi[i] || !visj[j] || !vis1[i+j]|| !vis2[i-j+10]){
                bool f1 = visi[i], f2 = visj[j], f3 = vis1[i+j], f4 = vis2[i-j+10];
                visi[i] = visj[j] = vis1[i+j] = vis2[i-j+10] = true;
                if(dfs(d+1,i,j))return true;
                visi[i] = f1; visj[j] = f2; vis1[i+j] = f3; vis2[i-j+10] = f4;
            }

    }
    return false;
}

int main()
{
    int cas = 0;
    while(scanf("%d%d",&n,&m),n){
        for(int i = 0;i < n; i++) scanf("%s",G[i]);
        for(maxd = 1; maxd < 5; maxd++){
            memset(visi,0,sizeof(visi));
            memset(visj,0,sizeof(visj));
            memset(vis1,0,sizeof(vis1));
            memset(vis2,0,sizeof(vis2));
            if(dfs(0,0,0))break;
        }
        printf("Case %d: %d\n",++cas,maxd);
    }
    return 0;
}

第一种剪枝

3.可以逐行(或逐列)放置。还有一个剪枝就是最多放5个,所以maxd==4还没有解,直接输出5.

0.201s

#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<<1];

bool dfs(int d,int si)
{
    if(d == maxd){
        for(int i = 0; i < n; i++)
            for(int j = 0; j < m; j++){
                if(G[i][j] == ‘X‘&&!visi[i]&&!visj[j]&&!vis1[i+j]&&!vis2[i-j+10])
                    return false;
            }
        return true;
    }
      for(int i = si; i < n; i++){
            for(int j = 0; j < m; j++)
            if(!visi[i] || !visj[j] || !vis1[i+j]|| !vis2[i-j+10]){
                bool f1 = visi[i], f2 = visj[j], f3 = vis1[i+j], f4 = vis2[i-j+10];
                visi[i] = visj[j] = vis1[i+j] = vis2[i-j+10] = true;
                if(dfs(d+1,i+1))return true;
                visi[i] = f1; visj[j] = f2; vis1[i+j] = f3; vis2[i-j+10] = f4;
            }

    }
    return false;
}

int main()
{
    int cas = 0;
    while(scanf("%d%d",&n,&m),n){
        for(int i = 0;i < n; i++) scanf("%s",G[i]);
        for(maxd = 1; maxd < 5; maxd++){
            memset(visi,0,sizeof(visi));
            memset(visj,0,sizeof(visj));
            memset(vis1,0,sizeof(vis1));
            memset(vis2,0,sizeof(vis2));
            if(dfs(0,0))break;
        }
        printf("Case %d: %d\n",++cas,maxd);
    }
    return 0;
}
时间: 2024-08-08 13:53:35

UVA 11214 Guarding the Chessboard 守卫棋盘(迭代加深+剪枝)的相关文章

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

UVA 10160 Servicing Stations(状态压缩+迭代加深)

[题目链接] LInk [题目大意] 给出一些点和边,选择一个点就能把这个点和相邻的点都覆盖,求最小点覆盖 [题解] 我们压缩点被覆盖的状态,迭代加深搜索覆盖的最小点数, 当剩余的点全部选上时都无法完全覆盖就剪枝. [代码] #include <cstdio> #include <algorithm> using namespace std; typedef long long LL; const int N=36; int i,n,m,x,y,limit; LL st[N],Lf

1374 - Power Calculus (迭代加深+剪枝)

题目要求乘除法的最少次数,其实就是一个数组中一开始只有一个数:1 ,每次可以从数组中取两个数(可以取同一个数)相加生成一个新数加如数组 . 那么显然这是一个迭代加深搜索,从小到大枚举深度上限 . 为了降低时间复杂度,我们要尽量的减少迭代次数,所以我们优先做加法,并且优先将最大的两个数相加,这样可以最快的接近目标 . 当然,有一个很显然的剪枝: 当每次取最大的两个数相加仍然小于n时要剪枝 .因为以最快的方式增长的话其指数是按照2的幂次增加的,所以当前最大值maxv*pow(2,maxd-d) <

11214 - Guarding the Chessboard(暴力搜索)

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

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

uva 11212 - Editing a Book(迭代加深搜索 IDA*) 迭代加深搜索

迭代加深搜索 自己看的时候第一遍更本就看不懂..是很水,但智商捉急也是没有办法的事情. 好在有几个同学已经是做过了这道题并且对迭代加深搜索的思路有了一定的了解,所以在某些不理解的地方询问了一下他们的见解, 真的是很有帮助,也许自己想要想很久才能想明白,还会很痛苦,稍微问一下别人的想法,点上一个方向,剩下的自己就能想得明白了. 迭代加深. 把answer(需要的步数或其他)在主函数里面从零往上递加,此之谓 "层数",亦可谓之"深度".用书上的话就是: 从小到大枚举深度

UVA 1343 - The Rotation Game-[IDA*迭代加深搜索]

解题思路: 这是紫书上的一道题,一开始笔者按照书上的思路采用状态空间搜索,想了很多办法优化可是仍然超时,时间消耗大的原因是主要是: 1)状态转移代价很大,一次需要向八个方向寻找: 2)哈希表更新频繁: 3)采用广度优先搜索结点数越来越多,耗时过大: 经过简单计算,最长大概10次左右的变换就能出解,于是笔者就尝试采用IDA*,迭代加深搜索的好处是: 1)无需存储状态,节约时间和空间: 2)深度优先搜索查找的结点数少: 3)递归方便剪枝: 代码如下: 1 #include <iostream> 2

UVA 11212 Editing a Book [迭代加深搜索IDA*]

11212 Editing a Book You have n equal-length paragraphs numbered 1 to n. Now you want to arrange them in the order of 1, 2, . . . , n. With the help of a clipboard, you can easily do this: Ctrl-X (cut) and Ctrl-V (paste) several times. You cannot cut

Power Calculus UVA - 1374 迭代加深搜索

迭代加深搜索经典题目,好久不做迭代加深搜索题目,拿来复习了,我们直接对当前深度进行搜索,注意剪枝,还有数组要适当开大,因为2^maxd可能很大 题目:题目链接 AC代码: 1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cmath> 5 #include <algorithm> 6 #include <cstring> 7 #incl