专题一搜索 G - Guarding the Chessboard

  1. 题目
    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-markedsquares.

    Input
    The input consists of at most 15 test cases. Each case begins witha line containing two integers n, m (1 < n, m < 10) the size ofthe chessboard. Next n lines each contain m characters, ‘X’ denotesmarked square, ‘.’ denotes unmarked squares. The last case isfollowed by a single zero, which should not be processed.
    Output
    For each test case, print the case number and the minimal number of queens needed.

    Sample Input
    8 8
    XXXXXXXX
    XXXXXXXX
    XXXXXXXX
    XXXXXXXX
    XXXXXXXX
    XXXXXXXX
    XXXXXXXX
    XXXXXXXX
    8 8
    X.......
    .X......
    ..X.....
    ...X....
    ....X...
    .....X..
    ......X.
    .......X
    0
    Sample Output
    Case 1: 5
    Case 2: 1
  2. 思路
    八皇后问题的改编,不过看到有点低的通过数我意识到这玩意可能没那么简单
    最后用了个东西叫迭代加深搜索
    简单点说:八皇后问题一般都是dfs(算是dfs样板题),而为了在有限时间以内得到最优结果,每次深搜的时候限制搜索深度,依次尝试只放一个皇后两个皇后n个皇后可不可行,可行时停止加深输出结果。此外运行一次可以知道10*10放满的情况下最多5个皇后就能保卫棋盘,所以搜完4个皇后还没得到结果的话,答案肯定是5个皇后。
  3. 代码
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    using namespace std;
    
    int n,m;
    int vis[4][25];
    int dep;//当前深度
    char map[15][15];
    
    bool dfs(int num,int r)//个数,行数
    {
    	if(num>dep)
    	{
    		for(int i=1;i<=n;i++)
    		{
    			for(int j=1;j<=m;j++)
    			if(map[i][j]=='X'&&!vis[0][i]&&!vis[1][j]&&!vis[2][i+j]&&!vis[3][i-j+m])
    				return 0;
    		}
    		return 1;
    	}	
    	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+m])
    			{
    				int v1=vis[0][i],v2=vis[1][j],v3=vis[2][i+j],v4=vis[3][i-j+m];
    				vis[0][i]=1, vis[1][j]=1, vis[2][i+j]=1, vis[3][i-j+m]=1;
    				if(dfs(num+1,i+1)) return 1;
    				vis[0][i]=v1,vis[1][j]=v2,vis[2][i+j]=v3,vis[3][i-j+m]=v4;
    			}
    		}
    	}
    	return 0;
    }
    
    int main()
    {
    	int q=1;
    	while(scanf("%d",&n)!=EOF&&n!=0)
    	{
    		scanf("%d",&m);
    		getchar();
    		for(int i=1;i<=n;i++){
    			for(int j=1;j<=m;j++){
    				scanf("%1c",&map[i][j]);
    			}
    			getchar();
    		}
    		for(dep=1;dep<5;dep++)//10*10放满只需要5个皇后,搜完4个还没结果直接出答案
    		{
    			memset(vis,0,sizeof(vis));
    			if(dfs(1,1))  break;
    		}
    		printf("Case %d: %d\n",q++,dep);
    	}
    	return 0;
    }
posted @ 2022-01-23 22:14  Benincasa  阅读(24)  评论(0编辑  收藏  举报