SGU224 K皇后 DLX+打表

8 篇文章 0 订阅

       首先,没写N皇后的建议先把N皇后给做了,题解在这里:http://blog.csdn.net/night_raven/article/details/19146023

    

       N*N的棋盘放K个皇后,0<=K<=n*n..之前一直没想好K皇后怎么转化成精确覆盖问题,因为它行列都不一定全部覆盖,而DLX在搜的时候,它是按照一个固定的顺序,一行一行的删除的,后来想了想,枚举到一行的时候,只要能添加一种“不放置”的选择,那么在搜完K行的时候得到的就是一组解。实现的话,建表和N皇后一样,搜索的时候有些变动,不放置的选择对应一个假删除,就是只把矩阵中对应棋盘上该行的一列的列表头删除而矩阵中的内容不变,这样既没有在这这里放置皇后,又避免了下一次枚举到这个不放置的行。虽说写是写完了,交上去居然T掉了=...反正一共就10*10种情况,果断打表...打出所有的情况也就用了十几秒的时间,一定是SGU时间卡的太死了= =.....

打表的程序:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
typedef long long ll;
const int tt=60;
const int maxr=tt*tt;
const int maxc=6*tt;
const int maxn=maxr*maxc;
int col[maxn],row[maxn],R[maxn],L[maxn],U[maxn],D[maxn];
int ct[10];
int a[55];
int sp;
int head[tt][tt];

int S[maxr];
int size,mRow;
int n,m,k;
struct ANS
{
    int x,y;
}ans[maxr];

int anss[330];
int st[maxr];

struct DLX
{
    void resume(int c)
    {
        L[R[c]]=c;
        R[L[c]]=c;
        for (int i=U[c]; i!=c; i=U[i])
        for (int j=L[i]; j!=i; j=L[j])
        {
            U[D[j]]=j;
            D[U[j]]=j;
            ++S[col[j]];
        }
    }
    void remove(int c)
    {
        L[R[c]]=L[c];
        R[L[c]]=R[c];
        for (int i=D[c]; i!=c; i=D[i])
        for (int j=R[i]; j!=i; j=R[j])
        {
            U[D[j]]=U[j];
            D[U[j]]=D[j];
            --S[col[j]];
        }
    }
    void init(int m)
    {
        for (int i=1; i<=m; i++)
        {
            L[i]=i-1;
            R[i]=i+1;
            U[i]=D[i]=i;
            S[i]=0;
            col[i]=i;
            row[i]=0;
        }
        L[0]=m;
        R[0]=1;
        R[m]=0;
        U[0]=D[0]=0;
        size=m;
        mRow=0;
    }
    int makehead(int c)
    {
        size++;
        S[c]++;
        col[size]=c;
        row[size]=mRow;
        L[size]=R[size]=size;

        U[size]=c;
        D[size]=D[c];
        U[D[size]]=D[U[size]]=size;
        return size;
    }
    void addcol(int id,int c)
    {
        size++;
        S[c]++;
        col[size]=c;
        row[size]=mRow;

        L[size]=id;
        R[size]=R[id];
        L[R[size]]=R[L[size]]=size;

        U[size]=c;
        D[size]=D[c];
        U[D[size]]=D[U[size]]=size;
    }
    void addrow(int i,int j)
    {
        int id;
        mRow++;
        ans[mRow].x=i;
        ans[mRow].y=j;
        id=makehead(i+ct[0]);
        head[i][j]=id;
        addcol(id,j+ct[1]);
        addcol(id,i+j+ct[2]);
        addcol(id,i-j+n-1+ct[3]);
    }
    bool dfs(int k)
    {
        if (k==m)
        {
//            for (int i=0; i<k; i++)
//            if (a[ans[st[i]].x]==0)anss[ans[st[i]].x]=ans[st[i]].y;
//            for (int i=0; i<k; i++)
//            cout<<ans[st[i]].x+1<<" "<<ans[st[i]].y+1<<endl;
            sp++;
//            cout<<anss[0]+1;
//            for (int i=1; i<n; i++)
//            cout<<" "<<anss[i]+1;
//            cout<<endl;
//            sp++;
            return true;
        }
        int c=0;
        int minn=(1<<28);
        for (int i=R[0]; i<=n; i=R[i])
        {
            if (!S[i]) continue;
            if (S[i]<minn)
            {
                minn=S[i];
                c=i;
            }
        }
        if (c==0) return false;

        for (int ii=0; ii<2; ii++)
        if (ii==0)
        {
        remove(c);
        for (int i=D[c]; i!=c; i=D[i])
        {
            st[k]=row[i];
            for (int j=R[i]; j!=i; j=R[j]) remove(col[j]);
            dfs(k+1);
            for (int j=L[i]; j!=i; j=L[j]) resume(col[j]);
        }
        resume(c);

        }
        else
        {
            L[R[c]]=L[c];
            R[L[c]]=R[c];
            dfs(k);
            L[R[c]]=c;
            R[L[c]]=c;
        }
        return false;
    }
}dlx;
int main()
{
//    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
      for (n=0; n<=10; n++)
       for (m=0; m<=10; m++)
       {
        if (m==0) cout<<endl;
        if (m>n || n==0)
        {
//            cout<<0<<endl;
            cout<<0<<",";
            continue;
        }
        else if (m==0)
        {

//            cout<<1<<endl;
            cout<<1<<",";
            continue;
        }
        ct[0]=1;
        ct[1]=n+1;
        ct[2]=(n<<1)+1;
        ct[3]=(n<<2);

        dlx.init(6*n-2);
        for (int i=0; i<n; i++)
         for (int j=0; j<n; j++)
         {
             dlx.addrow(i,j);
         }
         int k=0;
         ans[0].x=ans[0].y=0;
         sp=0;
         dlx.dfs(0);
//         cout<<sp<<endl;
         cout<<sp<<",";
    }
    return 0;
}



表:

#include <iostream>
int ans[11][11]=
{
0,0,0,0,0,0,0,0,0,0,0,
1,1,0,0,0,0,0,0,0,0,0,
1,4,0,0,0,0,0,0,0,0,0,
1,9,8,0,0,0,0,0,0,0,0,
1,16,44,24,2,0,0,0,0,0,0,
1,25,140,204,82,10,0,0,0,0,0,
1,36,340,1024,982,248,4,0,0,0,0,
1,49,700,3628,7002,4618,832,40,0,0,0,
1,64,1288,10320,34568,46736,22708,3192,92,0,0,
1,81,2184,25096,131248,310496,312956,119180,13848,352,0,
1,100,3480,54400,412596,1535440,2716096,2119176,636524,56832,724
};
using namespace std;

int main()
{
    int a,b;
    while(cin>>a>>b)
    {
        if (b>a)
        {
            cout<<0<<endl;
        }
        else
        cout<<ans[a][b]<<endl;
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值