回溯算法——入门
题目如下:
题目大意
在一个最大为4*4的方格内建blockhouse(
碉堡)
但是有条件
1. 两个及以上blockhouse不能位于同一行或者同一列
2. 如果有wall,两个blockhouse可以位于其两侧
3. blockhouse只能建在空地
注意的点
1. 多次输入;输入0时,结束
思路:
按上图顺序进行dfs,按下面代码进行k与map[x][y]中的x和y的转换
if(k%n == 0) {
x=(k-1)/n;
y=n-1;
}
else{
y = k%n-1;
x = k/n;
}
AC——C++代码:
比较low,>_<
有一些输出的注释,自己调试使用的
#include"cstdio"
#include "iostream"
using namespace std;
int best ;
char map[4][4];
int n;
bool judge(int x, int y){
bool a=true,b=true,c=true;
for(int i=x-1;i>=0;i--){
//printf("%c\n",map[i][y]);
if(map[i][y] == 'O') {b = false;break;}
if(map[i][y] == 'X') {b = true;break;}
}
for(int i=y-1;i>=0;i--){
// printf("%c\n",map[x][i]);
if(map[x][i] == 'O') {a = false;break;}
if(map[x][i] == 'X') {a = true; break;}
}
//cout<<a<<b<<endl;
c = a&&b;
return c;
}
void backtrack(int k, int count){
//printf("k:%d count:%d\n",k,count);
int x,y;
if(k >n*n){
if(count > best)
best = count;
return ;
}
if(k%n == 0) {
x=(k-1)/n;
y=n-1;
}
else{
y = k%n-1;
x = k/n;
}
//printf("x:%d y:%d\n",x,y);
if(map[x][y] == '.' && judge(x, y)){
// printf("%c\n",map[x][y]);
map[x][y] = 'O';
backtrack(k+1, count+1);
map[x][y] = '.';
}
backtrack(k+1, count);
}
int main(){
char ch;
while(scanf("%d",&n)&&n!=0){
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
map[i][j] = '.';
}
//二维字符数组
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>ch;
map[i][j] = ch;
}
}
//计算
best = 0;
backtrack(1, 0);
printf("%d\n", best);
}
return 0;
}
/*自己程序出问题的例子
3
...
..X
.X.
3
...
..X
.XX
*/
总结:
其实对于这道题,自己之前的一个小错误,我调试了好久,我思考了一下,归根到底还是因为自己对回溯算法的不熟悉。
然后自己又尝试另一种方法去再次看回溯算法,发现其实它就是dfs的思想,然后也是按树的先根顺序进行搜索,需要自己发现的就是:进入左子树搜索时的条件,进入右子树搜索的条件,以及一些减枝的条件。