题解:UVA11214 守卫键盘 Guarding the Chessboard

题意:输入一个 n×mn\times m 棋盘,某些格子有标记。用最少的皇后守卫(即占据或者攻击)所有带标记的格子。

分析:因为不知道放几个皇后可以守卫所有带标记的格子,即回溯法求解时解答树的深度没有明显的上限,所以使用迭代加深搜索。

将棋盘的每个格子标记为 0n×m10\sim n\times m-1,依次枚举守卫的皇后个数,枚举当前守卫的皇后个数下所有的放置情况,看是否能全部守卫。(枚举方式:ii 枚举 1n1\sim njj 枚举 i+1ni+1\sim n

AC code:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1005;
string s[maxn];
int vis[maxn][maxn];
int v[maxn][maxn];
int t;
int n,m;
bool check(){
	for(int i=0;i<n;i++){//判断所有被标记的正方形是否被保护
		for(int j=0;j<m;j++){
			if(v[i][j]&&!vis[0][i]&&!vis[1][j]&&!vis[2][j+i]&&!vis[3][j-i+n])
				return 0;
		}
	}
	return 1;
}
bool dfs(int cur,int pos,int tot){
	if(cur==tot){//放置tot个皇后是否可全保护
		if(check()){
			cout<<"Case "<<t<<": "<<tot<<endl;
			return 1;
		}
		return 0;
	}
	for(int i=pos;i<=n*m;i++){//所有点被标记成0~n*m-1
		int x=i/m;//当前位置的横坐标
		int y=i%m;
		int tmp1=vis[0][x];
		int tmp2=vis[1][y];
		int tmp3=vis[2][x+y];
		int tmp4=vis[3][y-x+n];
		vis[0][x]=vis[1][y]=vis[2][x+y]=vis[3][y-x+n]=1;
		if(dfs(cur+1,i+1,tot)){
			return 1;//此处优化,i+1下次枚举是当前位置再加1,避免情况重复
		}
		vis[0][x]=tmp1;
		vis[1][y]=tmp2;
		vis[2][x+y]=tmp3;
		vis[3][y-x+n]=tmp4;
	}
	return 0;//枚举当前所有情况不满足
}
signed main(){
	while(cin>>n){
		if(n==0){
			break;
		}
		t++;
		cin>>m;
		memset(v,0,sizeof(v));
		for(int i=0;i<n;i++){
			cin>>s[i];
		}
		for(int i=0;i<n;i++){
			for(int j=0;j<m;j++){
				if(s[i][j]=='X'){
					v[i][j]=1;
				}
			}
		}
		for(int i=0;;i++){
			memset(vis,0,sizeof(vis));
			if(dfs(0,0,i)){
				break;
			} 
		}
	}
	return 0;
}
posted @ 2024-09-01 15:28  KK_SpongeBob  阅读(20)  评论(0)    收藏  举报  来源