LA_2659_POJ_3076_ZOJ_3122_Sudoku(DancingLinksX精確覆蓋,數獨題模板)

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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章