ZOJ1002 Fire Net(非递归版)

以前用递归的回溯搜索思路做过一次,参ZOJ1002 Fire Net(递归版),今天想着用非递归的方法试试看,呵呵,比我想象中要难啊,主要还是堆栈里究竟放什么,这一点上思路一直没理清。因此用了整整一天的时间,总算用非递归的方法把1002AC掉了,在代码中我引入了堆栈层次的概念,模拟系统堆栈的行为,并且在搜索时加入了剪枝,但代码写得还是很烂,继续思考如何改进。

/********************************
Written by : phinecos(洞庭散人)
Data       : 2/11/2008 16:30
Description: 非递归,模拟系统堆栈解决类似八皇后问题
State : Accepted
Run Time: 0ms
Run Memory:    184KB
***************************************
*/

#include
<iostream>
#include 
<stack>
using namespace std;

const int MAXSIZE = 4;// 地图最大大小
char map[MAXSIZE][MAXSIZE];// 地图
int maxNum,n;

struct Node
{
    
int row;//
    int col;//
    int level;//当前层次
};

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)
{
    stack
<Node> s1;//解决树堆栈
    Node node;
    
int row,col,i;
    
int curLevel = 0;//当前层次

    
//起始结点入栈
    node.row=k/n;
    node.col 
= k%n;
    node.level 
= curLevel;//当前堆栈层次是第0层
    s1.push(node);

    
while (!s1.empty())
    {
        node 
= s1.top();
        row 
= node.row;
        col 
= node.col;
            
        
if (map[row][col]=='.'&&CanPut(row,col)==true)
        {
//map[row][col]空闲并且经测试可以放置,则占据此位置
            map[row][col] = 'O';
            
//堆栈层次加1
            curLevel++;
            node.level 
= curLevel;//作为这个堆栈层此的排头兵
            s1.pop();
            s1.push(node);
            curNum
++;//放置的棋子数目加1
        }

        
if (row==n-1&&col==n-1)
        {
//来到这个堆栈层的最后一个结点了
            if (curNum>maxNum)
            {
//保存这一层的最大数目
                maxNum = curNum;
            }
            
if (curLevel==0)
            {
//若回到第0层,则说明已经考虑完所有情况了
                break;
            }

            
/*
            *下面这段代码非常低级趣味,我居然用了两重while循环,It's rubbish,不喜勿进!!!!
            
*/

            
//去掉当前堆栈层
            while (!s1.empty())
            {
                node 
= s1.top();
                
if (node.level==curLevel)
                {
                    s1.pop();
                    
--k;
                }
                
else
                {
                    curLevel
--;
                    curNum
--;
                    
break;
                }
            }
            
//有一种情况是栈此时是空的,但还是需要将层次数和棋子数减1,因为循环中它给跳过去了。。。汗。
            if(s1.empty())
            {
                curLevel
--;
                curNum
--;
            }
            
//将上一层的排头兵恢复回来(就是把'O'再此变回'.',并且层次改为这一层)
            ++k;
            row 
= k/n;
            col 
= k%n;
            map[row][col] 
= '.';
            node.row 
= row;
            node.col 
= col;
            node.level 
= curLevel;
            s1.push(node);
            
//以上一层排头兵的下一个结点为起点,继续
            if (k+1<n*n)
            {
                
++k;
                node.row 
= k/n;
                node.col 
= k%n;
                node.level 
= curLevel;
                s1.push(node);
            }
            
else
            {
//当来到最后一个元素时,又有一个特殊的情形,此时当前层次所有情况都已经考虑完毕,因此需要将当前堆栈层给清空掉,哎,这个清空动作和前面是一样的,可居然又单独列了遍代码,吐了。。。
                if (curLevel==0)
                {
                    
break;
                }
                
while (!s1.empty())
                {
                    node 
= s1.top();
                    
if (node.level==curLevel)
                    {
                        s1.pop();
                        
--k;
                    }
                    
else
                    {
                        curLevel
--;
                        curNum
--;
                        
break;
                    }
                }

                
if (s1.empty())
                {
                    curLevel
--;
                    curNum
--;
                }
                
++k;
                row 
= k/n;
                col 
= k%n;
                map[row][col] 
= '.';
                node.row 
= row;
                node.col 
= col;
                node.level 
= curLevel;
                s1.push(node);

                
++k;
                node.row 
= k/n;
                node.col 
= k%n;
                node.level 
= curLevel;
                s1.push(node);
            }
            
        }
        
else
        {
//还没来到这一堆栈层次的最后一个节点,继续吧
            ++k;
            node.row 
= k/n;
            node.col 
= k%n;
            node.level 
= curLevel;
            s1.push(node);
        }
    }
}

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;
}

posted on 2008-11-02 16:43  Phinecos(洞庭散人)  阅读(1875)  评论(2编辑  收藏  举报

导航