POJ-3074(DLX,精确覆盖)

Sudoku

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 11071   Accepted: 3969

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

Source

Stanford Local 2006

#include<stdio.h>
#include<string.h>
#include <cmath>
#define INF 0x3f3f3f3f
#define MAXM 740
#define MAXN 330
int S[MAXN],H[MAXM];
int L[MAXM*MAXN],R[MAXM*MAXN],U[MAXM*MAXN],D[MAXM*MAXN],Row[MAXM*MAXN],Col[MAXM*MAXN];
int adj[MAXM][MAXN];
int ans[10][10];
//这道题的ID就是正常的i*m+j,不是ID++构造的,ID++自然是更精简,但失去了矩阵数字的规律
void init(int n,int m)    //如果是邻接表的输入方式的话,构造出来的一定是个正方形。
{
	for(int i=0;i<=m;i++)
	{
		S[i]=0;
		L[i]=i-1;
		R[i]=i+1;
		U[i]=i;
		D[i]=i;  //底下一个col上下连接就就好理解了
	}
	L[0]=m;     //双向循环链表
	R[m]=0;
	for(int i=0;i<=n;i++)
    H[i]=-1;
}
//将第row行第col列第id个结点加入数据结构
void link(int row,int col,int id)   //row,col的下标是从1开始的,
{
    //存第i个结点的行列值,id表示是第几个结点,最开始的一排也是结点,称作列头结点,U,D,的值也是他们的id,有值的结点是从m+1开始的
	Row[id]=row;   //再次强调,最开始的一排也是结点,最开始的一排结点左右是0.
	Col[id]=col;   //存第i个结点的行列值
	U[id]=U[col];  //用链表去理解
	D[id]=col;
	D[U[col]]=id;
	U[col]=id;
	if(H[row]==-1)        //列设H数组是因为R,L存的不是对应的位置。而U,D,是对应ID的,所以不用设H数组。
    H[row]=L[id]=R[id]=id;//每一行的开头都有个head的头结点,才发现H的头结点就是元素的ID,而且H是不画在图中的,H只是起一个临时作用。
	else
	{
		L[id]=L[H[row]];
		R[L[H[row]]]=id;
		R[id]=H[row];
		L[H[row]]=id;
	}
	S[col]++;
}
void exact_remove(int c)
{
    L[R[c]]=L[c];
    R[L[c]]=R[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];
            S[Col[j]]--;
       }
    }
}
void exact_resume(int 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]]=j;
            D[U[j]]=j;
            S[Col[j]]++;
        }
    }
    L[R[c]]=c;
    R[L[c]]=c;
}
int dfs(int d)
{
    if(R[0]==0)
    return 1;
    int c=R[0];
    int i,j;
    for(i=R[0];i!=0;i=R[i])  //这只是第1~324列的枚举
    {
        if(S[i]<S[c])
        c=i;
    }
    exact_remove(c);
    for(i=D[c];i!=c;i=D[i]) //这里的i是下标
    {
        int r=(i-1)/324;  //i>=325,所以r>=1;但r<=729这个就表示是第几行吧
        int key=r%9;     // r=9*(t-1)+k; k=r%9;
        if(key==0)
        key=9;
        int num=(r+8)/9;  //num>=1
        int x=(num+8)/9;
        int y=num%9;
        if(y==0)
        y=9;                        //利用下标找值的规律。 //利用枚举时建立的规律
        ans[x][y]=key;             //adj[9*(t - 1) + k][81+(i-1)*9+k]=1;
                                   //adj[9*(t - 1) + k][162+(j-1)*9+k]=1
                                   //r%9==k,一晚上才看出来
                                   //t每加1,行数加9,就是说列每加1,行数加9,这样y=(r+8)/9%9,
                                   //加8是因为这部分是k变化引起的行变化
                                   //在加一层,就是x的变化
        for(j=R[i];j!=i;j=R[j])
        {
            exact_remove(Col[j]);
        }
        if (dfs(d+1))
        return 1;
        /*这个顺序很重要,删除和恢复的方向必须相反
        开始相同,都是向右的,结果TLE了*/
        for (j=L[i];j!=i;j=L[j])
        {
            exact_resume(Col[j]);
        }
    }
    exact_resume(c);
    return 0;
}
//套用模板的前提是,构造出该01矩阵,本题是四种约束条件构造的的01矩阵
int main()
{
    int n,m;
    n=729;   //9*9*9   行数,对应种类数。
    m=324;   //4*9*9   列数,
    char str[85];
    int i,j,k;
    while(scanf("%s",str)!= EOF)
    {
        if(strcmp(str,"end")==0)
        break;
        memset(adj,0,sizeof(adj));
        for(i=1;i<=9;i++)          //i,j就是i行j列
        {
             for(j=1;j<=9;j++)
             {
                int t=9*(i-1)+j;  //t刚好是序列号
                if(str[t-1]=='.') //因为str下标是从0开始的,所以才要减个1.
                {
                   for(k=1;k<=9;k++)
                   {
                   //01矩阵的建立
                   /*
                       1. 行数:n*n*n n*n个格子; 每个格子有n种情况 所以有n*n*n种情况
                       2. 列数:4*n*n种情况 ,正如下面每一行都对应4种情况
                       3.
                   */
                   //adj[i][j]表示舞蹈链中的i行j列
                   adj[9*(t - 1) + k][t]=1;              //每个格子都需要填一个数,t就是所要填的数,让他变为1就表示t这个数在这种情况可填
                   adj[9*(t - 1) + k][81+(i-1)*9+k]=1;   //每一行1~9这几个数都必须出现一次,表示第i行已经有这个数k
                   adj[9*(t - 1) + k][162+(j-1)*9+k]=1;  //每一列1~9这几个数都必须出现一次,表示第j列已经有这个数k
                   adj[9*(t - 1) + k][243+(3*((i-1)/3)+(int)ceil(1.0*j/3)-1)*9+k]=1; //每个较小的个格子中1~9这几个数都必须出现一次,
                                                                          //表示第(3*((i-1)/3)+(int)ceil(1.0*j/3)宫格已经有k这个值
                  }
                 //adj[i]这个i,没有特殊意义,只是在列的参数下去凑12345。
               }
               else //一旦确定了就该种,种类自然就确定了,不用枚举,自然总的总类就会减少,这不是废话吗?
               {
                   k=str[t-1]-'0';                     //
                   adj[9*(t-1)+k][t]=1;
                   adj[9*(t-1)+k][81+(i-1)*9+k]=1;     //
                   adj[9*(t-1)+k][162+(j-1)*9+k]=1;
                   adj[9*(t-1)+k][243+(3*((i-1)/3)+(int)ceil(1.0*j/3)-1)*9+k]=1;
               }
            }
       }
       init(n,m);
       int id;
       for(i=1;i<=n;i++)
		{
			for(j=1;j<=m;j++)
			{
				if(adj[i][j]==1)
				{
					id=i*m+j;
					link(i,j,id);
				}
			}
		}
       dfs(0);
       for(i=1;i<=9;i++)
       {
        for(j=1;j<=9;j++)
        printf("%d",ans[i][j]);
       }
       printf("\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xigongdali/article/details/81277321
今日推荐