dancing link 解决八皇后

http://blog.sina.com.cn/s/blog_51cea4040100gwqw.html  八皇后  dancing link 


 话说,N皇后把ccy折磨了N久,写了x个版本,结果都是每每writing结束后,猛然发现,这种想法又有漏洞,然后Ctrl+A再Delete,晕……o(╯□╰)o……

    网上有看到说N皇后问题是个重复覆盖问题,于是,ccy朝这个方向想了N久,然后,提出了2个特点,实在不觉得重复覆盖模型可以解决这个N皇后。下面,让ccy把这几个问题摆出来。

    我是这样建的模型,把行当做皇后可放的格子,把列当做所有格子。那么,一个行,既在某个地方放下一个皇后会影响哪些格子。然后,做重复覆盖问题。接着,就囧掉了。怎么重复覆盖?选一些行,使某些列有1,明显不对呀!为什么不对?

    1、我们要选取一些行,而行数是定了的,为N行。

    2、棋盘里的格子被覆盖有两种情况,一是格子上放的皇后,那么,就不能有其他皇后再影响这格,二是格子被覆盖是因为其他位置的皇后影响了,这样,就可以有其他皇后再影响这个位置。

    有了这两个性质,ccy就很纠结地发现,我没有办法用重复覆盖或者精确覆盖来解决。希望有大牛来帮帮忙,指条明路,O(∩_∩)O谢谢~

**************************************************************************************************

http://www.spoj.pl/problems/NQUEEN/

1771. Yet Another N-Queen Problem
Problem code: NQUEEN


After solving Solution to the n Queens Puzzle by constructing, LoadingTime wants to solve a harder version of the N-Queen Problem. Some queens have been set on particular locations on the board in this problem. Can you help him??

Input
The input contains multiple test cases. Every line begins with an integer N (N<=50), then N integers followed, representing the column number of the queen in each rows. If the number is 0, it means no queen has been set on this row. You can assume there is at least one solution.

Output
For each test case, print a line consists of N numbers separated by spaces, representing the column number of the queen in each row. If there are more than one answer, print any one of them.

Example
Input:
4 0 0 0 0
8 2 0 0 0 4 0 0 0

Output:
2 4 1 3
2 6 1 7 4 8 3 5

**************************************************************************************************

题目大意,一个N*N的棋盘中,有些皇后已经放下,求一个可行性方案。

**************************************************************************************************

    话说,ccy首先做的事是老老实实地写过米字链,主要是因为,刚接触DLx,于是就傻乎乎地单单用了所谓的Links结构而已。然后,当时,写的是求所有解,测了个N=30的,发觉很没效率,就抛弃它了。

    但是,就刚刚,ccy改了下,求一解的情况,然后交了下代码,然后,囧掉。居然,比我第一次交的DLX算法还快,内牛满面!!!!

    其实,关于这个米字链,我觉得大家可以无视它的,真的,偏偏它还最有速度。

    棋盘上的行对应行,棋盘上的列对应列,然后,没有放皇后的地方标号为1,放了皇后的地方,就删除它和它可影响的地方。

    于是乎,这就是个非常单纯的暴力搜索,只是在处理矛盾的时候,是采用链表来删除而已,保证每次我们从矩阵中取出的1的格子都与前面所取的不冲突。

    至于代码,如果今天天气特别好,偏偏你又不想出去晒太阳吹河风,那么,就看ccy这个很无敌的代码吧!!

    (看了一下,也没得好长,就200多点点而已,本来以为很长很长很长的!!(⊙o⊙)…)

【搜索】Dancing <wbr>Links——N皇后问题


#include<iostream>
using namespace std;

const int maxn=55;

int L[maxn*maxn],R[maxn*maxn],U[maxn*maxn],D[maxn*maxn],AL[maxn*maxn],AR[maxn*maxn],BL[maxn*maxn],BR[maxn*maxn];
int Cd[maxn*maxn],Rd[maxn*maxn],Ad[maxn*maxn],Bd[maxn*maxn];
int map[maxn][maxn];
int nRow[maxn*maxn],nCol[maxn*maxn];
int S[maxn];
int n,cnt,head;
int stack[maxn*maxn*2],tot;

int total;
int ans[maxn];
bool ans_get;

void Ins_cnt(int x)
{
    L[x]=R[x]=U[x]=D[x]=AL[x]=AR[x]=BL[x]=BR[x]=x;
}

void Ins_Column(int x)
{
    cnt++;

    Ins_cnt(cnt);

    L[R[head]]=cnt;
    R[cnt]=R[head];
    L[cnt]=head;
    R[head]=cnt;

    Cd[x]=cnt;
}

void Ins_Row(int x)
{
    cnt++;
    Ins_cnt(cnt);
    Rd[x]=cnt;
}

void Ins_A(int x)
{
    cnt++;
    Ins_cnt(cnt);
    Ad[x]=cnt;
}

void Ins_B(int x)
{
    cnt++;
    Ins_cnt(cnt);
    Bd[x]=cnt;
}

void Ins(int cnt,int head,int L[],int R[])
{
    L[R[head]]=cnt;
    R[cnt]=R[head];
    L[cnt]=head;
    R[head]=cnt;
}

void Ins_node(int r,int c)
{
    int hd;

    cnt++;
    map[r][c]=cnt;

    hd=Cd[c];
    Ins(cnt,hd,U,D);
    hd=Rd[r];
    Ins(cnt,hd,L,R);
    hd=Ad[r+c-1];
    Ins(cnt,hd,AL,AR);
    hd=Bd[n-r+c];
    Ins(cnt,hd,BL,BR);

    nRow[cnt]=r;
    nCol[cnt]=c;
}

void init()
{
    head=0;
    Ins_cnt(head);
    cnt=0;
    tot=0;
    stack[tot]=-1;

    for (int i=1;i<=n;i++)
    {
        S[i]=n;
        Ins_Column(i);
    }
    for (int i=1;i<=n;i++)
        Ins_Row(i);
    for (int i=1;i<2*n;i++)
        Ins_A(i);
    for (int i=1;i<2*n;i++)
        Ins_B(i);
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
            Ins_node(i,j);
}

void move(int x)
{
    if (!nRow[x]) return;
    tot++;
    stack[tot]=x;
    L[R[x]]=L[x]; R[L[x]]=R[x];
    U[D[x]]=U[x]; D[U[x]]=D[x];
    AL[AR[x]]=AL[x]; AR[AL[x]]=AR[x];
    BL[BR[x]]=BL[x]; BR[BL[x]]=BR[x];
    S[nCol[x]]--;
}

void Remove(int x)
{
    for (int i=D[x];i!=x;i=D[i])
        move(i);
    for (int i=L[x];i!=x;i=L[i])
        move(i);
    for (int i=AL[x];i!=x;i=AL[i])
        move(i);
    for (int i=BL[x];i!=x;i=BL[i])
        move(i);
    move(x);
    tot++;
    stack[tot]=-1;
}

void sume(int x)
{
    if (!nRow[x]) return;
    S[nCol[x]]++;
    L[R[x]]=R[L[x]]=U[D[x]]=D[U[x]]=AL[AR[x]]=AR[AL[x]]=BL[BR[x]]=BR[BL[x]]=x;
}

void Resume()
{
    tot--;
    while (stack[tot]!=-1)
    {
        sume(stack[tot]);
        tot--;
    }
}

void dfs()
{
    if (ans_get) return;

    if (R[head]==head)
    {
        ans_get=true;
        printf("%d",ans[1]);
        for (int i=2;i<=n;i++)
            printf(" %d",ans[i]);
        printf("\n");
        return;
    }

    int minnum=INT_MAX;
    int c;
    for (int i=R[head];i!=head;i=R[i])
    {
        if (!ans[nCol[D[i]]] && !S[nCol[D[i]]]) return;
        if (S[nCol[D[i]]]<minnum)
        {
            minnum=S[nCol[D[i]]];
            c=i;
        }
    }

    R[L[c]]=R[c];
    L[R[c]]=L[c];
    for (int i=D[c];i!=c;i=D[i])
    {
        ans[nRow[i]]=nCol[i];
        Remove(i);
        dfs();
        if (ans_get) return;
        Resume();
    }
    R[L[c]]=L[R[c]]=c;
}

int main()
{
    freopen("data.in","r",stdin);
    freopen("data.out","w",stdout);

while (scanf("%d",&n)!=EOF)
{
    memset(nRow,0,sizeof(nRow));
    memset(nCol,0,sizeof(nCol));
    init();
    for (int i=1;i<=n;i++)
    {
        int j;
        scanf("%d",&j);
        if (j)
        {
            R[L[j]]=R[j];
            L[R[j]]=L[j];
            ans[i]=j;
            Remove(map[i][j]);
        }
    }
    ans_get=false;
    dfs();
}

    fclose(stdin);
    fclose(stdout);
    return 0;
}
**************************************************************************************************

    下面,是这文的重头戏,Dancing Links。

 

    对于任意一格,如果我们放了一个皇后,那么,这个格子所在的行,列,左斜线,右斜线都不能再放皇后了。那么,对于一格而言,实际上它影响的就正是这四个东西:行,列,左斜线,右斜线。那么,我们可以定义这四个东东为列,定义每个格子为行。这样问题就转换成一个精确覆盖了。

    我们拿棋盘的a行(在我们构造的图中为b列)来说吧。如果,我选取了b列,那么其他会影响b列的格子,必然是在棋盘中的a行上,那么就不能再选取。所以,这题就巧妙地转换为一个精确覆盖的模型了。

 

    在一个N*N的棋盘中,构造的图的行为N*N。

    列为:棋盘中的行数+棋盘中的列数+棋盘中的左斜线数+棋盘中的右斜线数=N+N+2*N-1+2*N-2=6*N-2。

 

    构好图后,就是很基础滴01矩阵精确覆盖模型了。

【搜索】Dancing <wbr>Links——N皇后问题

#include<iostream>
using namespace std;

const int maxn=55;
const int maxc=55*6;
const int maxr=55*55;
const int maxt=maxc+maxr*4;

int L[maxt],R[maxt],U[maxt],D[maxt];
int S[maxc];
int nCol[maxt],nRow[maxt];
int head[maxn][maxn];

int n,cnt;
int a[maxn];
bool used[maxr];
bool ans_get;

bool first_check()
{
    for (int i=1;i<n;i++)
        for (int j=i+1;j<=n;j++)
            if (a[i] && a[j])
                if (a[i]==a[j] || i+a[i]==j+a[j] || i-a[i]==j-a[j]) return false;
    return true;
}

void Ins_node(int cnt,int c)
{
    U[D[c]]=cnt;
    D[cnt]=D[c];
    U[cnt]=c;
    D[c]=cnt;
    S[c]++;
    nCol[cnt]=c;
}

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])
        {
            D[U[j]]=D[j];
            U[D[j]]=U[j];
            S[nCol[j]]--;
        }
}

void Resume(int c)
{
    for (int i=U[c];i!=c;i=U[i])
        for (int j=L[i];j!=i;j=L[j])
        {
            D[U[j]]=U[D[j]]=j;
            S[nCol[j]]++;
        }
    L[R[c]]=R[L[c]]=c;
}

void dfs(int k)
{
    if (k>n)
    {
        ans_get=true;
        return;
    }

    int c,minnum=INT_MAX;
    for (int i=R[0];i<=n;i=R[i])
    {
        if (!S[i]) return;
        if (S[i]<minnum)
        {
            minnum=S[i];
            c=i;
        }
    }

    Remove(c);
    for (int i=U[c];i!=c;i=U[i])
    {
        used[nRow[i]]=1;
        for (int j=R[i];j!=i;j=R[j])
            Remove(nCol[j]);
        dfs(k+1);
        if (ans_get) return;
        used[nRow[i]]=0;
        for (int j=L[i];j!=i;j=L[j])
            Resume(nCol[j]);
    }
    Resume(c);
}

int main()
{
    freopen("data.in","r",stdin);
    freopen("data.out","w",stdout);

    while (scanf("%d",&n)!=EOF)
    {
        for (int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for (int i=0;i<=n*6-2;i++)
        {
            S[i]=0;
            L[i]=i-1; R[i]=i+1;
            U[i]=D[i]=i;
        }
        L[0]=n*6-2; R[n*6-2]=0;

        ans_get=false;
        if (!first_check())
        {
            printf("-1\n");
            continue;
        }

        cnt=n*6-2;
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
            {
                for (int k=1;k<=4;k++)
                {
                    L[cnt+k]=cnt+k-1;
                    R[cnt+k]=cnt+k+1;
                    nRow[cnt+k]=(i-1)*n+j;
                }
                L[cnt+1]=cnt+4;
                R[cnt+4]=cnt+1;
                Ins_node(cnt+1,i);
                Ins_node(cnt+2,n+j);
                Ins_node(cnt+3,n*2+i+j-1);
                Ins_node(cnt+4,n*5+i-j-1);
                head[i][j]=cnt+1;
           

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页