题目:
输入一个n*m的棋盘(n,m<10),某些格子有标记,用最少的皇后守卫(即占据或攻击)所有的标记的格子。输出皇后的个数。
思路:
一开始没有想到用迭代加深搜索,直接dfs结果还没写完就发现这样要枚举的量太大了……于是换用迭代加深搜索。对于每个格子有四个方向可以用i,j,i+j,i+j+maxn(下标要是正的)表示,当cur等于枚举的答案maxd就判断是不是所有的标记都被攻击了。
另外如果这个格子放上了皇后,那该皇后所在行的后边的格子就没必要枚举了,直接跳到下一行的开头就可以了。
将二维数组线性表示的代码:
#include <bits/stdc++.h> #define inf 0x3f3f3f3f #define MAX 1e3 #define FRE() freopen("in.txt","r",stdin) #define FRO() freopen("out.txt","w",stdout) using namespace std; typedef long long ll; const int maxn = 15; char mp[maxn][maxn]; int vis[4][maxn*2]; int n,m,maxd; bool isok(){//判断所有的标记是不是都已经被攻击 for(int i=0; i<n; i++){ for(int j=0; j<m; j++){ if(mp[i][j]=='X' && !vis[0][i] && !vis[1][j] && !vis[2][i+j] && !vis[3][i-j+maxn]){ return false; } } } return true; } bool dfs(int now, int cur){ if(cur==maxd){ return isok() ? true : false; } for(int k=now; k<n*m; k++){ int i = k/n,j = k%m; vis[0][i]++; vis[1][j]++; vis[2][i+j]++; vis[3][i-j+maxn]++;//对四个方向进行标记 if(dfs((i+1)*m,cur+1)){ return true; } vis[0][i]--;vis[1][j]--;vis[2][i+j]--;vis[3][i-j+maxn]--;//恢复四个方向dfs之前的状态 } return false; } int main(){ //FRE(); int kase = 0; while(scanf("%d",&n) && n){ scanf("%d",&m); getchar(); for(int i=0; i<n; i++){ gets(mp[i]); } memset(vis,0,sizeof(vis)); for(maxd = 0;; maxd++){ if(dfs(0,0)){ break; } } printf("Case %d: %d ",++kase,maxd); } return 0; }
正常二维数组表示代码:
#include <bits/stdc++.h> #define inf 0x3f3f3f3f #define MAX 1e3 #define FRE() freopen("in.txt","r",stdin) #define FRO() freopen("out.txt","w",stdout) using namespace std; typedef long long ll; const int maxn = 15; char mp[maxn][maxn]; int vis[4][maxn*2]; int n,m,maxd; bool isok(){//判断所有的标记是不是都已经被攻击 for(int i=0; i<n; i++){ for(int j=0; j<m; j++){ if(mp[i][j]=='X' && !vis[0][i] && !vis[1][j] && !vis[2][i+j] && !vis[3][i-j+maxn]){ return false; } } } return true; } bool dfs(int x,int y, int cur){ if(cur==maxd){ return isok() ? true : false; } for(int i=x; i<n; i++){ for(int j=y; j<m; j++){ vis[0][i]++; vis[1][j]++; vis[2][i+j]++; vis[3][i-j+maxn]++;//对四个方向进行标记 if(dfs(i+1,0,cur+1)){//这一行后边的都不用遍历了,直接跳到下一行的开头就可以了 return true; } vis[0][i]--;vis[1][j]--;vis[2][i+j]--;vis[3][i-j+maxn]--;//恢复四个方向dfs之前的状态 } } return false; } int main(){ //FRE(); int kase = 0; while(scanf("%d",&n) && n){ scanf("%d",&m); getchar(); for(int i=0; i<n; i++){ gets(mp[i]); } for(maxd = 0;; maxd++){ memset(vis,0,sizeof(vis)); if(dfs(0,0,0)){ break; } } printf("Case %d: %d ",++kase,maxd); } return 0; }