dancing links

例①:精确覆盖:
POJ 3074 Sudoku:

Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 12526 Accepted: 4470
Description

In the game of Sudoku, you are given a large 9 × 9 grid divided into smaller 3 × 3 subgrids. For example,

. 2 7 3 8 . . 1 .
. 1 . . . 6 7 3 5
. . . . . . . 2 9
3 . 5 6 9 2 . 8 .
. . . . . . . . .
. 6 . 1 7 4 5 . 3
6 4 . . . . . . .
9 5 1 8 . . . 7 .
. 8 . . 6 5 3 4 .
Given some of the numbers in the grid, your goal is to determine the remaining numbers such that the numbers 1 through 9 appear exactly once in (1) each of nine 3 × 3 subgrids, (2) each of the nine rows, and (3) each of the nine columns.

Input

The input test file will contain multiple cases. Each test case consists of a single line containing 81 characters, which represent the 81 squares of the Sudoku grid, given one row at a time. Each character is either a digit (from 1 to 9) or a period (used to indicate an unfilled square). You may assume that each puzzle in the input will have exactly one solution. The end-of-file is denoted by a single line containing the word “end”.

Output

For each test case, print a line representing the completed Sudoku puzzle.

Sample Input

.2738…1…1…6735…293.5692.8…6.1745.364…9518…7…8…6534.
…52…8.4…3…9…5.1…6…2…7…3…6…1…7.4…3.
end
Sample Output

527389416819426735436751829375692184194538267268174593643217958951843672782965341
416837529982465371735129468571298643293746185864351297647913852359682714128574936

精确覆盖数独:

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<map>
#include<ctime>
#include<vector>
#define ll long long
#define llu unsigned ll
//#define int ll
using namespace std;
const int N=9;
const int mr=N*N*N+10;
const int mc=N*N*4+10;
const int maxn=mr*4+10;
char str[mc];

struct DLX
{
    int n,m,si;
    int u[maxn],d[maxn],r[maxn],l[maxn],row[maxn],col[maxn];
    int h[mr],s[mc];
    int ans[mc];

    void init(int nn,int mm)
    {
        n=nn,m=mm;
        for(int i=0;i<=m;i++)
        {
            s[i]=0;
            u[i]=d[i]=i;
            l[i]=i-1,r[i]=i+1;
        }
        l[0]=m,r[m]=0;
        si=m;
        for(int i=1;i<=n;i++)
            h[i]=-1;
    }

    void add(int rr,int cc)
    {
        si++;
        row[si]=rr;
        col[si]=cc;
        s[cc]++;

        d[si]=d[cc];
        u[d[cc]]=si;
        u[si]=cc;
        d[cc]=si;

        if(h[rr]<0) h[rr]=l[si]=r[si]=si;
        else
        {
            r[si]=r[h[rr]];
            l[r[h[rr]]]=si;
            l[si]=h[rr];
            r[h[rr]]=si;
        }
    }

    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 _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]]=j;
                u[d[j]]=j;
                s[col[j]]++;
            }
        }
        l[r[c]]=r[l[c]]=c;
    }

    bool dance(int st)
    {
        if(r[0]==0)
        {
            for(int i=0;i<st;i++) str[(ans[i]-1)/9]=(ans[i]-1)%9+'1';
            for(int i=0;i<N*N;i++) putchar(str[i]);
            putchar('\n');
            return true;
        }

        int c=r[0];
        for(int i=r[0];i!=0;i=r[i])
            if(s[i]<s[c]) c=i;

        _remove(c);
        for(int i=d[c];i!=c;i=d[i])
        {
            ans[st]=row[i];
            for(int j=r[i];j!=i;j=r[j]) _remove(col[j]);
            if(dance(st+1)) return true;
            for(int j=l[i];j!=i;j=l[j]) _resume(col[j]);
        }
        _resume(c);
        return false;
    }
};


void get_p(int &rr,int &c1,int &c2,int &c3,int &c4,int i,int j,int k)
{
    rr=(i*N+j)*N+k;
    c1=i*N+j+1;
    c2=N*N+i*N+k;
    c3=N*N*2+j*N+k;
    c4=N*N*3+((i/3)*3+(j/3))*N+k;
}


DLX sp;

int main(void)
{
    while(scanf("%s",str),str[0]!='e')
    {
        sp.init(N*N*N,N*N*4);
        int rr,c1,c2,c3,c4;
        for(int i=0;i<N;i++)
        {
            for(int j=0;j<N;j++)
            {
                for(int k=1;k<=N;k++)
                {
                    if(str[i*N+j]=='.'||str[i*N+j]=='0'+k)
                    {
                        get_p(rr,c1,c2,c3,c4,i,j,k);
                        sp.add(rr,c1);
                        sp.add(rr,c2);
                        sp.add(rr,c3);
                        sp.add(rr,c4);
                    }
                }
            }
        }
        sp.dance(0);
    }
    return 0;
}

例②:精确覆盖:
hihoCoder #1321 : 搜索五·数独:

时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
在上一次学会了跳舞链的搜索方法之后,小Ho觉得这个算法真是棒极了。

小Ho:小Hi,还有没有什么有意思的题目可以用跳舞链解决的啊?

小Hi:我想想,首先可以确定的是给出01矩阵的精确覆盖问题都可以解决。

小Ho:嗯,我觉得如果一个问题能够通过模型转换成01矩阵,应该都可以用跳舞链解决吧。

小Hi:是的,那么小Ho,你觉得数独问题能用跳舞链解决么?

小Ho:数独是啥?

小Hi:小Ho,你居然不知道数独?

小Ho:我有听过,但是没有实际去做过。

小Hi:这样啊,那我就简单给你讲一讲。数独问题就是给定一个9x9的矩阵。然后将1~9填入当中,比如下面这个:

1.jpg
其中有些格子已经填好了,有些格子则需要你填进去。

对于填好后的格子,需要满足3个条件:

每一个数字在每一行只能出现1次
每一个数字在每一列只能出现1次
每一个数字在每一个九宫区域内只能出现1次,上图中每一个粗线包围的区域就是一个九宫。
小Ho:规则看上去还是蛮简单的嘛。

小Hi:对啊。那么你觉得这个问题可以用跳舞链解决么?

小Ho:嗯,我想一想啊。

提示:数独

输入
第1行:1个正整数t,表示数据组数,2≤t≤5

接下来t组数据,每组按照如下格式给出:

第1…9行:9个整数,可能包含0~9。0表示该格未填写数字,其他数字表示该格已经填写有该数字。

输出
与输入数据相对应的t组输出数据:

第1…9行:9个整数,表示第i组数据完成后的状态,满足数独的要求,保证每组数据有且仅有一组合法解。

样例输入
1
4 0 0 0 7 0 1 0 0
0 0 1 9 0 4 6 0 5
0 0 0 0 0 1 0 0 0
0 0 0 7 0 0 0 0 2
0 0 2 0 3 0 0 0 0
8 4 7 0 0 6 0 0 0
0 1 4 0 0 0 8 0 6
0 2 0 0 0 0 3 0 0
6 0 0 0 9 0 0 0 0
样例输出
4 9 6 5 7 3 1 2 8
3 8 1 9 2 4 6 7 5
2 7 5 8 6 1 9 4 3
1 5 3 7 8 9 4 6 2
9 6 2 4 3 5 7 8 1
8 4 7 2 1 6 5 3 9
7 1 4 3 5 2 8 9 6
5 2 9 6 4 8 3 1 7
6 3 8 1 9 7 2 5 4

稍微一改就好啦:

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<map>
#include<ctime>
#include<vector>
#define ll long long
#define llu unsigned ll
//#define int ll
using namespace std;
const int N=9;
const int mr=N*N*N+10;
const int mc=N*N*4+10;
const int maxn=mr*4+10;
int a[mc];

struct DLX
{
    int n,m,si;
    int u[maxn],d[maxn],r[maxn],l[maxn],row[maxn],col[maxn];
    int h[mr],s[mc];
    int ans[mc];

    void init(int nn,int mm)
    {
        n=nn,m=mm;
        for(int i=0;i<=m;i++)
        {
            s[i]=0;
            u[i]=d[i]=i;
            l[i]=i-1,r[i]=i+1;
        }
        l[0]=m,r[m]=0;
        si=m;
        for(int i=1;i<=n;i++)
            h[i]=-1;
    }

    void add(int rr,int cc)
    {
        si++;
        row[si]=rr;
        col[si]=cc;
        s[cc]++;

        d[si]=d[cc];
        u[d[cc]]=si;
        u[si]=cc;
        d[cc]=si;

        if(h[rr]<0) h[rr]=l[si]=r[si]=si;
        else
        {
            r[si]=r[h[rr]];
            l[r[h[rr]]]=si;
            l[si]=h[rr];
            r[h[rr]]=si;
        }
    }

    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 _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]]=j;
                u[d[j]]=j;
                s[col[j]]++;
            }
        }
        l[r[c]]=r[l[c]]=c;
    }

    bool dance(int st)
    {
        if(r[0]==0)
        {
            for(int i=0;i<st;i++) a[(ans[i]-1)/9]=(ans[i]-1)%9+1;
            for(int i=0;i<N;i++)
            {
                for(int j=0;j<N;j++)
                {
                    if(j!=0) putchar(' ');
                    printf("%d",a[i*N+j]);
                }
                putchar('\n');
            }
            return true;
        }

        int c=r[0];
        for(int i=r[0];i!=0;i=r[i])
            if(s[i]<s[c]) c=i;

        _remove(c);
        for(int i=d[c];i!=c;i=d[i])
        {
            ans[st]=row[i];
            for(int j=r[i];j!=i;j=r[j]) _remove(col[j]);
            if(dance(st+1)) return true;
            for(int j=l[i];j!=i;j=l[j]) _resume(col[j]);
        }
        _resume(c);
        return false;
    }
};


void get_p(int &rr,int &c1,int &c2,int &c3,int &c4,int i,int j,int k)
{
    rr=(i*N+j)*N+k;
    c1=i*N+j+1;
    c2=N*N+i*N+k;
    c3=N*N*2+j*N+k;
    c4=N*N*3+((i/3)*3+(j/3))*N+k;
}


DLX sp;

int main(void)
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        for(int i=0;i<N;i++)
        {
            for(int j=0;j<N;j++)
                scanf("%d",&a[i*N+j]);
        }
        sp.init(N*N*N,N*N*4);
        int rr,c1,c2,c3,c4;
        for(int i=0;i<N;i++)
        {
            for(int j=0;j<N;j++)
            {
                for(int k=1;k<=N;k++)
                {
                    if(a[i*N+j]==0||a[i*N+j]==k)
                    {
                        get_p(rr,c1,c2,c3,c4,i,j,k);
                        sp.add(rr,c1);
                        sp.add(rr,c2);
                        sp.add(rr,c3);
                        sp.add(rr,c4);
                    }
                }
            }
        }
        sp.dance(0);
    }
    return 0;
}



例③:可重复覆盖:
FZU 1686:
Problem 1686 神龙的难题

Accept: 980 Submit: 2878
Time Limit: 1000 mSec Memory Limit : 32768 KB
Problem Description

这是个剑与魔法的世界.英雄和魔物同在,动荡和安定并存.但总的来说,库尔特王国是个安宁的国家,人民安居乐业,魔物也比较少.但是.总有一些魔物不时会进入城市附近,干扰人民的生活.就要有一些人出来守护居民们不被魔物侵害.魔法使艾米莉就是这样的一个人.她骑着她的坐骑,神龙米格拉一起消灭干扰人类生存的魔物,维护王国的安定.艾米莉希望能够在损伤最小的前提下完成任务.每次战斗前,她都用时间停止魔法停住时间,然后米格拉他就可以发出火球烧死敌人.米格拉想知道,他如何以最快的速度消灭敌人,减轻艾米莉的负担.
Input

数据有多组,你要处理到EOF为止.每组数据第一行有两个数,n,m,(1<=n,m<=15)表示这次任务的地区范围. 然后接下来有n行,每行m个整数,如为1表示该点有怪物,为0表示该点无怪物.然后接下一行有两个整数,n1,m1 (n1<=n,m1<=m)分别表示米格拉一次能攻击的行,列数(行列不能互换),假设米格拉一单位时间能发出一个火球,所有怪物都可一击必杀.

Output

输出一行,一个整数,表示米格拉消灭所有魔物的最短时间.

Sample Input
4 4
1 0 0 1
0 1 1 0
0 1 1 0
1 0 0 1
2 2
4 4
0 0 0 0
0 1 1 0
0 1 1 0
0 0 0 0
2 2
Sample Output
4
1

题意一开始有点模糊:
给出大矩形的长宽, 矩形里面有1,0两个值, 给出小矩形的长宽, 求用最少的小矩形覆盖所有的1.
将她施法时的小矩块作为行,大矩阵内的敌人标记后作为列。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<map>
#include<ctime>
#include<vector>
#define ll long long
#define llu unsigned ll
//#define int ll
using namespace std;
const int inf=0x3f3f3f3f;
const int N=15;
const int mr=N*N+10;
const int mc=N*N+10;
const int maxn=mr*mc+10;

struct DLX
{
    int n,m,si;
    int u[maxn],d[maxn],r[maxn],l[maxn],row[maxn],col[maxn];
    int h[mr],s[mc];
    bool ha[mc];
    int ans;

    void init(int nn,int mm)
    {
        n=nn,m=mm;
        for(int i=0;i<=m;i++)
        {
            s[i]=0;
            u[i]=d[i]=i;
            l[i]=i-1,r[i]=i+1;
        }
        l[0]=m,r[m]=0;
        si=m;
        for(int i=1;i<=n;i++)
            h[i]=-1;
        ans=inf;
    }

    void add(int rr,int cc)
    {
        si++;
        row[si]=rr;
        col[si]=cc;
        s[cc]++;

        d[si]=d[cc];
        u[d[cc]]=si;
        u[si]=cc;
        d[cc]=si;

        if(h[rr]<0) h[rr]=l[si]=r[si]=si;
        else
        {
            r[si]=r[h[rr]];
            l[r[h[rr]]]=si;
            l[si]=h[rr];
            r[h[rr]]=si;
        }
    }

    void _remove(int c)
    {
        for(int i=d[c];i!=c;i=d[i])
            l[r[i]]=l[i],r[l[i]]=r[i];
    }

    void _resume(int c)
    {
        for(int i=u[c];i!=c;i=u[i])
            l[r[i]]=r[l[i]]=i;
    }

    int fi(void)
    {
        int cnt=0;
        for(int c=r[0];c!=0;c=r[c]) ha[c]=true;
        for(int c=r[0];c!=0;c=r[c])
        {
            if(ha[c])
            {
                cnt++;
                ha[c]=false;
                for(int i=d[c];i!=c;i=d[i])
                    for(int j=r[i];j!=i;j=r[j])
                        ha[col[j]]=false;
            }
        }
        return cnt;
    }

    void dance(int st)
    {
        if(st+fi()>=ans) return ;
        if(r[0]==0)
        {
            ans=min(ans,st);
            return ;
        }

        int c=r[0];
        for(int i=r[0];i!=0;i=r[i])
            if(s[i]<s[c]) c=i;

        for(int i=d[c];i!=c;i=d[i])
        {
            _remove(i);
            for(int j=r[i];j!=i;j=r[j]) _remove(j);
            dance(st+1);
            for(int j=l[i];j!=i;j=l[j]) _resume(j);
            _resume(i);
        }

    }
};

DLX sp;
int a[20][20];
int id[20][20];

int main(void)
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        int cnt=0;
        memset(id,0,sizeof(id));
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                scanf("%d",&a[i][j]);
                if(a[i][j]==1) id[i][j]=++cnt;
            }
        sp.init(n*m,cnt);


        int n1,m1;
        scanf("%d%d",&n1,&m1);
        int pm=1;

        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                for(int x=0;x<n1&&i+x<=n;x++)
                {
                    for(int y=0;y<m1&&j+y<=m;y++)
                    {
                        if(id[i+x][j+y])
                            sp.add(pm,id[i+x][j+y]);
                    }
                }
                pm++;
            }
        }
        sp.dance(0);
        printf("%d\n",sp.ans);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值