首页 > 代码库 > POJ 3076 数独DLX

POJ 3076 数独DLX

Sudoku
Time Limit: 10000MS Memory Limit: 65536K
Total Submissions: 4203 Accepted: 2051

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


题意:给定一个16*16的矩阵,有的格子已经填好了字母,有的没填好,要求填写‘a’-‘p‘的字母,每一行每一个字母只出现一次,每一列一个数字只出现一次,每一个4*4的方阵内每一个数字只出现一次,

DLX里的行代表决策,总共有16*16*16行,代表了某一行某一列填写某一个数字,列代表任务,一共有4种需要达成的任务,

(1):Slot(a,b第a行第b列需要有字母。

(2):ROW(a,b)第a行要有字母b

(3):COL(a,b)第a列需要有字母b

(4)SUB(a,b)第a个方阵需要有字母b。

则问题转化为行数为16*16*16,列数为16*16*4的0-1矩阵的精确覆盖问题,采用dlx搜索就可以得到答案。

代码:

/* ***********************************************
Author :_rabbit
Created Time :2014/5/1 8:56:15
File Name :F.cpp
************************************************ */
#pragma comment(linker, "/STACK:102400000,102400000")
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <string>
#include <time.h>
#include <math.h>
#include <queue>
#include <stack>
#include <set>
#include <map>
using namespace std;
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi acos(-1.0)
typedef long long ll;
struct DLX{
    const static int maxn=20010;
    #define FF(i,A,s) for(int i = A[s];i != s;i = A[i])
    int L[maxn],R[maxn],U[maxn],D[maxn];
    int size,col[maxn],row[maxn],s[maxn],H[maxn];
    bool vis[70];
	int ans[maxn],cnt;
    void init(int m){
        for(int i=0;i<=m;i++){
            L[i]=i-1;R[i]=i+1;U[i]=D[i]=i;s[i]=0;
        }
        memset(H,-1,sizeof(H));
        L[0]=m;R[m]=0;size=m+1;
    }
	void link(int r,int c){
         U[size]=c;D[size]=D[c];U[D[c]]=size;D[c]=size;
         if(H[r]<0)H[r]=L[size]=R[size]=size;
         else {
             L[size]=H[r];R[size]=R[H[r]];
             L[R[H[r]]]=size;R[H[r]]=size;
         }
         s[c]++;col[size]=c;row[size]=r;size++;
     }
	void del(int c){//精确覆盖
        L[R[c]]=L[c];R[L[c]]=R[c];  
        FF(i,D,c)FF(j,R,i)U[D[j]]=U[j],D[U[j]]=D[j],--s[col[j]];  
    }  
    void add(int c){  //精确覆盖
        R[L[c]]=L[R[c]]=c;  
        FF(i,U,c)FF(j,L,i)++s[col[U[D[j]]=D[U[j]]=j]];  
    }  
	bool dfs(int k){//精确覆盖
        if(!R[0]){  
            cnt=k;return 1;  
        }  
        int c=R[0];FF(i,R,0)if(s[c]>s[i])c=i;  
        del(c);  
        FF(i,D,c){  
            FF(j,R,i)del(col[j]);  
            ans[k]=row[i];if(dfs(k+1))return true;  
            FF(j,L,i)add(col[j]);  
        }  
        add(c);  
        return 0;
    }  
    void remove(int c){//重复覆盖
        FF(i,D,c)L[R[i]]=L[i],R[L[i]]=R[i];
    }
     void resume(int c){//重复覆盖
         FF(i,U,c)L[R[i]]=R[L[i]]=i;
     }
    int A(){//估价函数
        int res=0;
        memset(vis,0,sizeof(vis));
        FF(i,R,0)if(!vis[i]){
                res++;vis[i]=1;
                FF(j,D,i)FF(k,R,j)vis[col[k]]=1;
            }
        return res;
    }
    void dfs(int now,int &ans){//重复覆盖
        if(R[0]==0)ans=min(ans,now);
        else if(now+A()<ans){
            int temp=INF,c;
            FF(i,R,0)if(temp>s[i])temp=s[i],c=i;
            FF(i,D,c){
                remove(i);FF(j,R,i)remove(j);
                dfs(now+1,ans);
                FF(j,L,i)resume(j);resume(i);
            }
        }
    }
}dlx;
const int SLOT=0;
const int ROW=1;
const int COL=2;
const int SUB=3;
int encode(int a,int b,int c){
	return a*256+b*16+c+1;
}
void decode(int code,int &a,int &b,int &c){
	code--;
	c=code%16;code/=16;
	b=code%16;code/=16;
	a=code;
}
char str[20][20];
bool read(){
	for(int i=0;i<16;i++)
		if(scanf("%s",str[i])!=1)return false;
	return true;
}
int main()
{
     //freopen("data.in","r",stdin);
     //freopen("data.out","w",stdout);
     int T=0;
	 while(read()){
		 if(T)puts("");T++;
		 dlx.init(1024);
		 for(int r=0;r<16;r++)
			 for(int c=0;c<16;c++)
				 for(int k=0;k<16;k++)
					 if(str[r][c]==‘-‘||str[r][c]==‘A‘+k){
						 int p=encode(r,c,k);
						 dlx.link(p,encode(SLOT,r,c));
						 dlx.link(p,encode(ROW,r,k));
						 dlx.link(p,encode(COL,c,k));
						 dlx.link(p,encode(SUB,(r/4)*4+c/4,k));
					 }
		 dlx.dfs(0);
		 for(int i=0;i<dlx.cnt;i++){
			 int r,c,v;
			 decode(dlx.ans[i],r,c,v);
			 str[r][c]=‘A‘+v;
		 }
		 for(int i=0;i<16;i++)printf("%s\n",str[i]);
	 }
     return 0;
}