题目:
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1002
本来以为是一道和八皇后类似的题目,用的回溯,一层一层搜。最后发现了问题
这道题可以看作8皇后问题的变形题,但是还是花费了我不少时间并参考了网上的代码才弄出来。如前一篇文章所分析的一样,这个题目的递归调用结束点也在搜索的最后一个步骤。不同的是:8皇后问题里,每一行都一定要放一个皇后,所以递归结束点在放置皇后并且判断合法之后,而且只有在放置并合法之后才能继续尝试放置下一行。Fire Net不一样,它需要找出能够放置的最大个数,而且也不是每一行或者每一列都一定要放一个。所以它的递归结束点就是到达矩阵的末尾之时,而且可以在刚进入递归调用的时候就可以检查了。 8皇后问题需要8个步骤,即每一行都要探测(其中的一个约束条件使得只需要一步探测一行即可,而不需要探测每个方格)。Fire Net则需要n*n个步骤,即每个方格都要探测。和8皇后另一个不一样的地方是,Fire Net在放置合法后和放置失败后,都要继续向前探测直到结束为止。
下面是我参考的别人的代码:(来自洞庭散人)
http://www.cnblogs.com/phinecos/archive/2008/09/18/1293017.html
using namespace std;
char map[ 4 ][ 4 ]; // 地图
int maxNum,n;
bool CanPut( int row, int col)
{ // 测试是否可以放置碉堡到row行col列处,因为位置是从小到大前进的,因此只需要测试比待测试点小的位置
int i;
// 测试col列上是否有面对面的碉堡
for (i = row - 1 ; i >= 0 ; --i )
{
if (map[i][col] == ' O ' ) return false ;
if (map[i][col] == ' X ' ) break ;
}
// 测试row行上是否有面对面的碉堡
for (i = col - 1 ; i >= 0 ; --i )
{
if (map[row][i] == ' O ' ) return false ;
if (map[row][i] == ' X ' ) break ;
}
return true ;
}
void Solve( int k, int curNum)
{
int x,y;
if (k == n * n)
{ // 到最后一个了
if (curNum > maxNum)
{ // 保存当前遍历路径找到的最大值
maxNum = curNum;
return ;
}
}
else
{
x = k / n; // 行号
y = k % n; // 列号
if ((map[x][y] == ' . ' ) && (CanPut(x,y)== true ))
{ // 当前点是空白处,并且可以放置碉堡
map[x][y] = ' O ' ; // 放置碉堡
Solve(k + 1 ,curNum + 1 ); // 递归进入下一个位置
map[x][y] = ' . ' ; // 回溯
}
// 当前点不能放置或回溯回来
Solve(k + 1 ,curNum);
}
}
int main()
{
int i,j;
while (cin >> n && n != 0 )
{
// 输入地图
for (i = 0 ;i < n;i ++ )
{
for (j = 0 ;j < n;j ++ )
{
cin >> map[i][j];
}
}
maxNum = 0 ; // 最多可能放置的数目
// 开始深搜,起点设置为左上角
Solve( 0 , 0 );
cout << maxNum << endl;
}
return 0 ;
}