初涉关于精确覆盖的DLX

Dancing Links,跳动的舞者,的确是很飘的一种数据结构。

DL是双向循环十字链表,其作用大体就是对精确覆盖算法的一种优化,在递归搜索的过程中利用链表容易删增的特性提高了精确覆盖算法的效率。


强烈推一篇博客,讲述的很详细,弱就不多说了。

http://www.cnblogs.com/grenet/p/3145800.html


模板贴起来,自己写的有点挫。以最经典的9*9数独为例。


#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <cmath>
#include <stack>
#include <map>

#pragma comment(linker, "/STACK:1024000000")
#define EPS (1e-8)
#define LL long long
#define ULL unsigned long long
#define _LL __int64
#define INF 0x3f3f3f3f
#define Mod 100007

using namespace std;

const int MAXCLOUM = 9*9*4+10,MAXROW = 9*9*9+10,MAXPOINT = MAXROW*4 + MAXCLOUM;

int sta[MAXROW],sta_anw;//答案栈以及栈内元素个数
int SIZE[MAXCLOUM];//每一列元素个数,不包括虚拟列指针
int PRE[MAXROW];//每一行最后加入的元素位置,初始为-1.
int C[MAXCLOUM];//每一列的头指针的位置
int ROW[MAXPOINT],COL[MAXPOINT];//每个元素的行列坐标
int L[MAXPOINT],R[MAXPOINT],U[MAXPOINT],D[MAXPOINT];//每个元素的四个指针
int Top;//第一个未分配元素的地址

int Creat(int row = -1,int col = -1)
{
    ROW[Top] = row;
    COL[Top] = col;

    U[Top] = Top;
    D[Top] = Top;
    L[Top] = Top;
    R[Top] = Top;

    return Top++;
}

void Init(int row,int col)
{
    sta_anw = 0;
    Top = 0;
    C[0] = Creat(-1,0);
    for(int i = 1; i <= col; ++i)
    {
        C[i] = Creat(-1,i);
        R[C[i]] = R[C[i-1]];
        L[R[C[i-1]]] = C[i];
        R[C[i-1]] = C[i];
        L[C[i]] = C[i-1];
        SIZE[i] = 0;
    }

    memset(PRE,-1,sizeof(PRE));
}

void Insert(int row,int col)
{
    int now = Creat(row,col);

    D[U[C[col]]] = now;
    U[now] = U[C[col]];
    D[now] = C[col];
    U[C[col]] = now;
    ++SIZE[col];

    if(PRE[row] != -1)
    {
        L[R[PRE[row]]] = now;
        R[now] = R[PRE[row]];
        L[now] = PRE[row];
        R[PRE[row]] = now;
    }

    PRE[row] = now;
}

void Remove(int c)
{
    R[L[c]] = R[c];
    L[R[c]] = L[c];

    int i,j;

    for(i = D[c]; i != c; i = D[i])
    {
        for(j = R[i]; j != i ; j = R[j])
        {
            U[D[j]] = U[j],D[U[j]] = D[j];
            --SIZE[COL[j]];
        }
    }
}

void Resume(int c)
{
    int i,j;

    for(i = U[c]; i != c; i = U[i])
    {
        for(j = L[i]; j != i; j = L[j])
        {
            U[D[j]] = j,D[U[j]] = j;
            ++SIZE[COL[j]];
        }
    }

    R[L[c]] = c;
    L[R[c]] = c;
}

bool Dance()
{
    int now,i,j;

    if(R[C[0]] == C[0])
        return true;

    now = R[C[0]];

    for(i = now;i != C[0];i = R[i])
        if(SIZE[COL[i]] < SIZE[COL[now]])
            now = i;
    Remove(COL[now]);
    for(i = D[now]; i != now; i = D[i])
    {
        for(j = R[i]; j != i; j = R[j])
            Remove(C[COL[j]]);
        sta[sta_anw++] = ROW[i];
        if(Dance())
            return true;
        sta_anw--;

        for(j = L[i]; j != i; j = L[j])
            Resume(C[COL[j]]);
    }
    Resume(COL[now]);

    return false;
}

int num[10][10];

struct N
{
    int x,y,info;
}st[1000];

inline int CalPos(int x,int y)
{
    x = (x-1)/3 + 1;
    y = (y-1)/3 + 1;

    return (x-1)*3 + y;
}

int main()
{
    int T;

    bool bla = false;

    scanf("%d",&T);

    int ans,i,j,k;

    while(T--)
    {
        if(bla == false)
            bla = true;
        else
            puts("");

        for(i = 1;i <= 9; ++i)
        {
            for(j = 1;j <= 9; ++j)
                scanf("%1d",&num[i][j]);
        }

        Init(9*9*9,9*9*4);

        ans = 1;

        for(i = 1;i <= 9; ++i)
        {
            for(j = 1;j <= 9; ++j)
            {
                for(k = 1;k <= 9; ++k)
                {
                    if(num[i][j] == 0 || num[i][j] == k)
                    {
                        Insert(ans,(i-1)*9+k);
                        Insert(ans,81 + (j-1)*9+k);
                        Insert(ans,162 + (CalPos(i,j)-1)*9 + k);
                        Insert(ans,243 + (i-1)*9 + j);
                        st[ans++] = (N){i,j,k};
                    }
                }
            }
        }

        Dance();

        if(sta_anw)
        {
            for(i = 0;i < sta_anw; ++i)
                num[st[sta[i]].x][st[sta[i]].y] = st[sta[i]].info;
            for(i = 1;i <= 9; ++i)
            {
                for(j = 1;j <= 9; ++j)
                    printf("%d",num[i][j]);
                puts("");
            }
        }
        else
        {
            puts("Could not complete this grid.");
        }
    }

    return 0;
}





















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值