POJ 3074 Sudoku [DLX] [SDLX]

5 篇文章 0 订阅

Sudoku
Time Limit: 1000MS Memory Limit: 65536KB 64bit IO Format: %lld & %llu

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


舞蹈链解决数独问题。
转化成(9*9*9)*(4*9*9)的精确覆盖问题。

1~81列:在(i,j)有填数。
82~162列:在第i行填了数字num
163~243列:在第j列填了数字num
244~324列:在第N宫填了数字num

那么对于一个确定的格子,在原链表中加入一行,对应其四个关系。
对于一个点,在原链表中加入九行,对应其四个关系,分别是不同的数字。
这样的话,转化之后的矩阵就是答案需要覆盖的矩阵了。
可以把每一行对应的答案信息(i,j,num)储存下来。

但是会T。

优化:

  • IDLX , short label first
  • SDLX ,settled andconflict judge first

加了这两个优化之后就好可以很快出解了。


#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
const int INF=0x3f3f3f3f;
const int maxrow = 9*9*9+5;
const int maxcol = 4*9*9+5;
const int maxn = maxrow*maxcol;
struct Node
{
    int left,right,up,down;
    int row,col;
}node[maxn];
#define left(x) node[x].left 
#define right(x) node[x].right
#define up(x) node[x].up
#define down(x) node[x].down
#define row(x) node[x].row
#define col(x) node[x].col
int rows,cols;
int maxnode,mustselect;
int tot[maxcol];
int head;
inline void disable_row(int root)
{
    left(right(root)) = left(root);
    right(left(root)) = right(root);
}
inline void disable_col(int root)
{
    up(down(root)) = up(root);
    down(up(root)) = down(root);
}
inline void enable_row(int root)
{
    left(right(root)) = root;
    right(left(root)) = root;
}
inline void enable_col(int root)
{
    up(down(root)) = root;
    down(up(root)) = root;
}
inline void remove(int colnum)
{
    disable_row(colnum);
    for(int i=down(colnum);i^colnum;i=down(i))
        for(int j=right(i);j^i;j=right(j))
            disable_col(j),tot[col(j)]--; // needed toquery the exact current total value of the minimum column
}
inline void restore(int colnum)
{
    enable_row(colnum);
    for(int i=up(colnum);i^colnum;i=up(i))
        for(int j=left(i);j^i;j=left(j))
            enable_col(j),tot[col(j)]++;
}
inline void initialize()
{
    memset(node,0,sizeof(node));
    memset(tot,0,sizeof(tot));
    rows=0; cols=4*9*9;
    head=0;
    left(head)=cols; right(head)=1;
    for(int i=1;i<=cols;i++)
    {
        left(i) = i-1;
        right(i) = i+1;
        up(i) = i;
        down(i) = i;
        row(i) = 0;
        col(i) = i;
    }
    right(cols) = head;
    maxnode=cols;
    mustselect = 0;
}
struct Info
{
    int x,y;
    int num;
    Info(const int _x = 0,const int _y = 0,const int _num = 0)
    {
        x=_x; y=_y; num=_num;
    }
}val[maxrow];
int a[maxcol];
Info ans[maxrow];
int top;
void add_row(int a[maxcol],int cnt,Info info)
{
    rows++;
    val[rows] = info;
    for(int i=1;i<=cnt;i++)
    {
        maxnode++;
        tot[a[i]]++;
        if(i==1)
        {
            left(maxnode) = maxnode;
            right(maxnode) = maxnode;
        }
        else
        {
            left(maxnode) = maxnode-1;
            right(maxnode) = right(maxnode-1);
            enable_row(maxnode);
        }
        up(maxnode) = up(a[i]);
        down(maxnode) = a[i];
        enable_col(maxnode);
        col(maxnode) = a[i];
        row(maxnode) = rows;
    }
}
void insert_num(int i,int j,int num)
{
    int N = (i-1)/3*3 + (j-1)/3 + 1;
    a[1] = (i-1)*9 + j;
    a[2] = (i-1)*9 + num + 81;
    a[3] = (j-1)*9 + num + 162;
    a[4] = (N-1)*9 + num + 243;
    add_row(a,4,Info(i,j,num));
    ans[mustselect++] = val[rows];
    for(int i=1;i<=4;i++) tot[a[i]]=-1,remove(a[i]);
}
void insert_dot(int i,int j)
{
    int N = (i-1)/3*3 + (j-1)/3 + 1;
    a[1] = (i-1)*9 + j;
    a[2] = (i-1)*9 + 81;
    a[3] = (j-1)*9 + 162;
    a[4] = (N-1)*9 + 243;
    for(int k=1;k<=9;k++)
    {
        a[2]++; a[3]++; a[4]++;
        bool flag=true;
        for(int p=1;p<=4;p++)
            if(!~tot[a[p]]) flag=false;
        if(flag) add_row(a,4,Info(i,j,k));
    }
}
bool Dance(int k)
{
    int c1 = right(head);
    if(c1 == head)
    {
        top = k;
        return true;
    }
    for(int i=right(c1);i^head;i=right(i))
    {
        if(tot[i] < tot[c1]) c1 = i;
        if(!tot[i]) return false;
    }
    remove(c1);
    for(int i=down(c1);i^c1;i=down(i))
    {
        ans[k] = val[row(i)];
        for(int j=right(i);j^i;j=right(j)) remove(col(j));
        if(Dance(k+1)) return true;
        for(int j=left(i);j^i;j=left(j)) restore(col(j));
    }
    restore(c1);
    return false;
}
int g[100][100];
void print()
{
    memset(g,0,sizeof(g));
    for(int i=0;i<top;i++)
    {
        Info tmp = ans[i];
        g[tmp.x][tmp.y] = tmp.num;
    }
    for(int i=1;i<=9;i++)
        for(int j=1;j<=9;j++)
            putchar(g[i][j]+'0');
}
const int maxlen = 100;
char s[maxlen];
bool init()
{
    scanf("%s",s);
    if(s[0]=='e') return false;
    initialize();
    int pos=0;
    for(int i=1;i<=9;i++)
        for(int j=1;j<=9;j++)
        {
            if(s[pos]!='.') insert_num(i,j,s[pos]-'0');
            pos++;
        }
    pos=0;
    for(int i=1;i<=9;i++)
        for(int j=1;j<=9;j++)
        {
            if(s[pos]=='.') insert_dot(i,j);
            pos++;
        }
    return true;
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("sudo.in","r",stdin);
    freopen("sudo.out","w",stdout);
#endif
    bool flag = true;
    while(init())
    {
        if(!flag) putchar('\n');
        flag=false;
        Dance(mustselect);
        print();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值