ZOJ 1002

题目:

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

#include < iostream >
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 ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值