LA_2659_POJ_3076_ZOJ_3122_Sudoku(DancingLinksX精确覆盖,数独题模板)

13 篇文章 0 订阅
11 篇文章 0 订阅

Sudoku
Time Limit: 10000MS Memory Limit: 65536K
Total Submissions: 4918 Accepted: 2332

Description

A Sudoku grid is a 16x16 grid of cells grouped in sixteen 4x4 squares, where some cells are filled with letters from A to P (the first 16 capital letters of the English alphabet), as shown in figure 1a. The game is to fill all the empty grid cells with letters from A to P such that each letter from the grid occurs once only in the line, the column, and the 4x4 square it occupies. The initial content of the grid satisfies the constraints mentioned above and guarantees a unique solution. 
 
Write a Sudoku playing program that reads data sets from a text file.

Input

Each data set encodes a grid and contains 16 strings on 16 consecutive lines as shown in figure 2. The i-th string stands for the i-th line of the grid, is 16 characters long, and starts from the first position of the line. String characters are from the set {A,B,…,P,-}, where – (minus) designates empty grid cells. The data sets are separated by single empty lines and terminate with an end of file.

Output

The program prints the solution of the input encoded grids in the same format and order as used for input.

Sample Input

--A----C-----O-I
-J--A-B-P-CGF-H-
--D--F-I-E----P-
-G-EL-H----M-J--
----E----C--G---
-I--K-GA-B---E-J
D-GP--J-F----A--
-E---C-B--DP--O-
E--F-M--D--L-K-A
-C--------O-I-L-
H-P-C--F-A--B---
---G-OD---J----H
K---J----H-A-P-L
--B--P--E--K--A-
-H--B--K--FI-C--
--F---C--D--H-N-

Sample Output

FPAHMJECNLBDKOGI
OJMIANBDPKCGFLHE
LNDKGFOIJEAHMBPC
BGCELKHPOFIMAJDN
MFHBELPOACKJGNID
CILNKDGAHBMOPEFJ
DOGPIHJMFNLECAKB
JEKAFCNBGIDPLHOM
EBOFPMIJDGHLNKCA
NCJDHBAEKMOFIGLP
HMPLCGKFIAENBDJO
AKIGNODLBPJCEFMH
KDEMJIFNCHGAOPBL
GLBCDPMHEONKJIAF
PHNOBALKMJFIDCEG
IAFJOECGLDPBHMNK

Source



数独题目

只不过变成了16x16的数独……

正好也整理下数独模板

题目中给的数据好像是pdf直接拷贝出bug的缘故

poj的是正常的LA和ZOJ好像都有问题


基本点不变

如果数独是M*M的

那么有M*M*M行 

对应i行j列填数字k

M*M*4列

1~M*M i行j列有数字

M*M+1~M*M*2 i行有数字j

M*M*2+1~M*M*3 i列有数字j

M*M*3+1~M*M*4 i小九宫有数字j


特别测试

列的排布会大范围的影响速度

同样的程序如果交换“i行j列有数字”列与“i小九宫有数字j”列

效率会低10倍……

使用place函数可以方便的算出第几个小九宫

而且place变成类的成员函数速度更快(应该是被inline了,直接inline应该也可以……)


#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;

const int M=16;//数独大小
const int MN=M*M*M+10;
const int MM=M*M*4+10;
const int MNN=MN*4+MM; //最大点数,数独问题节点没有那么多

struct DLX
{
    int n,m,si;//n行数m列数si目前有的节点数
    //十字链表组成部分
    int U[MNN],D[MNN],L[MNN],R[MNN],Row[MNN],Col[MNN];
    //第i个结点的U向上指针D下L左R右,所在位置Row行Col列
    int H[MN],S[MM]; //记录行的选择情况和列的覆盖情况
    int ansd,ans[MN];
    void init(int _n,int _m)  //初始化空表
    {
        n=_n;
        m=_m;
        for(int i=0;i<=m;i++) //初始化第一横行(表头)
        {
            S[i]=0;
            U[i]=D[i]=i;      //目前纵向的链是空的
            L[i]=i-1;
            R[i]=i+1;         //横向的连起来
        }
        R[m]=0;L[0]=m;
        si=m;                 //目前用了前0~m个结点
        for(int i=1;i<=n;i++)
            H[i]=-1;
    }
    void link(int r,int c)    //插入点(r,c)
    {
        //cout<<"link r "<<r<<" c "<<c<<endl;
        ++S[Col[++si]=c];     //si++;Col[si]=c;S[c]++;
        Row[si]=r;
        D[si]=D[c];
        U[D[c]]=si;
        U[si]=c;
        D[c]=si;
        if(H[r]<0)
            H[r]=L[si]=R[si]=si;
        else
        {
            R[si]=R[H[r]];
            L[R[H[r]]]=si;
            L[si]=H[r];
            R[H[r]]=si;
        }
    }
    void remove(int c)        //列表中删掉c列
    {
        //cout<<"remove "<<c<<endl;
        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)        //恢复c列
    {
        //cout<<"resume "<<c<<endl;
        for(int i=U[c];i!=c;i=U[i])
            for(int j=L[i];j!=i;j=L[j])
                ++S[Col[U[D[j]]=D[U[j]]=j]];
        L[R[c]]=R[L[c]]=c;
    }
    bool dance(int d) //选取了d行
    {
        if(R[0]==0)//全部覆盖了
        {
            //全覆盖了之后的操作
            ansd=d;
            return 1;
        }
        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[d]=Row[i];
            for(int j=R[i];j!= i;j=R[j])
                remove(Col[j]);
            if(dance(d+1))
                return 1;
            for(int j=L[i];j!=i;j=L[j])
                resume(Col[j]);
        }
        resume(c);
        return 0;
    }
    void place(int &r,int &c1,int &c2,int &c3,int &c4,int i,int j,int k)
    {
        r=(i*M+j)*M+k;
        c1=M*M*0+i*M+j+1;
        c2=M*M*1+i*M+k;
        c3=M*M*3+j*M+k;
        c4=M*M*2+((i/4)*4+(j/4))*M+k;//确定第几个小九宫(16宫?),九宫4改3
    }
}dlx;

char ss[M+5][M+5];

int main()
{
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
    int ca=0;
    while(scanf("%s",ss[0])!=EOF)
    {
        for(int i=1;i<M;i++)
            scanf("%s",ss[i]);
        dlx.init(M*M*M,M*M*4);
        int r,c1,c2,c3,c4;
		for(int i = 0;i < M;i++)
			for(int j = 0;j < M;j++)
				for(int k = 1;k <= M;k++)
					if(ss[i][j] == '-' || ss[i][j] == 'A'+k-1)
					{
						dlx.place(r,c1,c2,c3,c4,i,j,k);
						dlx.link(r,c1);
						dlx.link(r,c2);
						dlx.link(r,c3);
						dlx.link(r,c4);
					}
        dlx.dance(0);
        int v,x,y;
        for(int i=0;i<dlx.ansd;i++)
        {
            v=(dlx.ans[i]-1)%M;
            x=(dlx.ans[i]-1)/M/M;
            y=(dlx.ans[i]-1)/M%M;
            ss[x][y]=v+'A';
        }
        if(ca++)
            printf("\n");
        for(int i=0;i<M;i++)
            printf("%s\n",ss[i]);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值