ZOJ 1002 最大堡垒数

///////////////////////////////////////////////
//最大堡垒数
//用回溯法(其实是N皇后问题的改装)+暴力A掉
#include<iostream>
#include<math.h>
using namespace std;
char a[5][5];

 


//堡垒类,方便对成员的访问
class Blockhouses
{
    friend int nBlock(int);
private:
    bool Place(int k);
    bool Place2(int k);
    void Backtrack(int t,int lever);
    int n,
        **x;
    int max;
};


//判断该位置能否放置堡垒
bool Blockhouses::Place(int k)
{
    int i,j;
    bool flags=1;
    if(k==-1 || k==0) return 1;      //由于在下面的调用中,k有可能小于0
    for(i=1;i<k;i++)   
    {
        //当列数相等时,判断x[i]与x[k]之间是否有墙
        if(x[i][2]==x[k][2])
        {
            flags=0;
            for(j=x[i][1]+1; j<x[k][1]; j++)
            {
                if(a[j][ x[i][2] ]=='X')
                    flags=1;
            }
            if(!flags) return 0;
        }
    }

    return flags;
}


//由于行数没有判断,所以加多一个判行数的
bool Blockhouses::Place2(int k)
{
    int j;
    //不同行的马上可以返回1
    if(x[k-1][1]!=x[k][1]) return 1;   

    //剩下的是行数相同的,判其中间是否有墙
    for(j=x[k-1][2]+1; j<x[k][2]; j++)
        if(a[ x[k][1] ][j]=='X')
            return 1;

    return 0;
}

 

//递归回溯函数
//    t记录当前放置的堡垒,lever是当前的行数,
//    note记录该行暂时放置的堡垒数,以便修改t
void Blockhouses::Backtrack(int t,int lever)
{
    int i,j,note;
    if(lever>n)
    {
        if(t-1>max)
            max=t-1;
    }

    else
    {
        //此循环是表示进入n叉树各个分支(以同一行的不同元素作为前一行各个元素的孩子)
        for(i=1;i<=n;i++)
        {
            note=0;
            //此循环是计算第lever行的堡垒
            for(j=i;j<=n;j++)
            {
                if(a[lever][j]!='X')
                {
                    x[t][1]=lever;
                    x[t][2]=j;
                    if(Place2(t))
                    {
                        t++;
                        note++;
                    }
                }
            }
            //当拉进的t-1与t-2堡垒符合要求时才往下一层(行)搜索
            if(Place(t-2) && Place(t-1))
                Backtrack(t,lever+1);
            t-=note;
            //注意到当第lever行没有拉进堡垒时,让其直接往下一层搜索,
            //即把第lever-1层与第lever+1层连起来
            if((t-1>0) && (x[t-1][1]<lever))
                Backtrack(t,lever+1);
        }
    }
}


//这函数是为了实现对成员的调用而设置
int nBlock(int n)
{
    int i,j;
    Blockhouses X;
    X.max=0;
    X.n=n;
    int **p=new int*[n*n+1];
    //p[](即x[])中用到p[][1]与p[][2]是要记录该堡垒的行列数
    for(i=0;i<=n*n;i++) p[i]=new int[3];
    for(i=0;i<=n*n;i++)    
        for(j=1;j<=2;j++)
            p[i][j]=0;
    X.x=p;
    X.Backtrack(1,1);
    for(i=0;i<=n*n;i++) delete []p[i];  //注意释放数组的形式
    return X.max;
}

 

int main()
{
    int n;
    while(cin>>n && n!=0)
    {
        int i,j;
        for(i=1;i<=n;i++)
            for(j=1;j<=n;j++)
                cin>>a[i][j];

        cout<<nBlock(n)<<endl;
    }

    return 0;
}

你可能感兴趣的:(ZOJ)