题目链接:UVa 639 - Don't Get Rooked
今天下午去看霍比特人2,无聊的要死,呃,不吐槽了,进入正题。
回溯题目,和八皇后有些区别,这道题加上了围墙,而且不限制对角线了,所以说一行就可能有多个棋子。这样的话需要全局回溯,就是说回溯算法里边应该有双重for循环,放置每一个棋子前判断一下当前位置是否合法。
开始想当然,很快的写了一个回溯,然后就错了,例子就没有通过。也贴出来,警示一下自己。错误原因:如果遍历到一个围墙,取消了围墙所在行和列的禁止标记,导致了下一个遍历就有可能将棋子放到围墙前边,而围墙前边有可能已经放置了棋子。
/**
错误的代码
*/
#include <iostream>
#include <cstring>
using namespace std;
const int MAX_N = 4 + 2;
char map[MAX_N][MAX_N];
int vis[MAX_N][MAX_N];
int n,_max;
int vis_col[MAX_N];
int vis_row[MAX_N];
void dfs(int cur)
{
int i,j;
for(i = 0;i < n;i++)
{
for(j = 0;j < n;j++)
{
if(map[i][j] == '.' && !vis_col[j] && !vis_row[i])
{
vis_row[i] = vis_col[j] = 1;
dfs(cur+1);
vis_row[i] = vis_col[j] = 0;
}
else if(map[i][j] == 'X')
{
vis_row[i] = vis_col[j] = 0;
}
}
}
if(cur > _max)
_max = cur;
}
int main()
{
while(cin>>n,n)
{
memset(map,0,sizeof(map));
memset(vis,0,sizeof(vis));
_max = -1;
int i,j;
for(i = 0;i < n;i++)
{
for(j = 0;j < n;j++)
{
cin>>map[i][j];
}
}
dfs(0);
cout<<_max<<endl;
}
return 0;
}
/**
正确的代码
*/
#include <iostream>
#include <cstring>
#include <stdio.h>
//#define test
using namespace std;
const int MAX_N = 4 + 2;
char map[MAX_N][MAX_N];
int vis[MAX_N][MAX_N];
int n,_max;
bool decide(int a,int b)
{
if(map[a][b] != '.' || vis[a][b] == 1)
return false;
int i;
for(i = a - 1; i >= 0;i--)
{
if(map[i][b] == 'X')
break;
if(vis[i][b] == 1)
return false;
}
for(i = a + 1; i < n;i++)
{
if(map[i][b] == 'X')
break;
if(vis[i][b] == 1)
return false;
}
for(i = b + 1; i < n;i++)
{
if(map[a][i] == 'X')
break;
if(vis[a][i] == 1)
return false;
}
for(i = b - 1; i >= 0;i--)
{
if(map[a][i] == 'X')
break;
if(vis[a][i] == 1)
return false;
}
return true;
}
void dfs(int cur)
{
int i,j;
for(i = 0;i < n;i++)
{
for(j = 0;j < n;j++)
{
if(decide(i,j))
{
vis[i][j] = 1;
dfs(cur+1);
vis[i][j] = 0;
}
}
}
if(cur > _max)
_max = cur;
}
int main()
{
#ifdef test
freopen("in.txt","r",stdin);
#endif // test
while(cin>>n,n)
{
memset(map,0,sizeof(map));
memset(vis,0,sizeof(vis));
_max = -1;
int i,j;
for(i = 0;i < n;i++)
for(j = 0;j < n;j++)
cin>>map[i][j];
dfs(0);
cout<<_max<<endl;
}
return 0;
}
本文针对UVa639-Don'tGetRooked问题进行了解析,对比了错误与正确代码的区别,重点在于如何在含有障碍物的棋盘上放置棋子而不违反规则,并详细阐述了正确的回溯算法实现。
287

被折叠的 条评论
为什么被折叠?



