HDU_4069_SquigglySudoku(DancingLinksX精确覆盖+BFS)

17 篇文章 0 订阅
11 篇文章 0 订阅

Squiggly Sudoku

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 1855    Accepted Submission(s): 758


Problem Description
Today we play a squiggly  sudoku, The objective is to fill a 9*9 grid with digits so that each column, each row, and each of the nine Connecting-sub-grids that compose the grid contains all of the digits from 1 to 9.
Left figure is the puzzle and right figure is one solution.

Now, give you the information of the puzzle, please tell me is there no solution or multiple solution or one solution.
 

Input
The first line is a number T(1<=T<=2500), represents the number of case. The next T blocks follow each indicates a case.
Each case contains nine lines, Each line contains nine integers.
Each module number tells the information of the gird and is the sum of up to five integers:
0~9: '0' means this gird is empty, '1' - '9' means the gird is already filled in.
16: wall to the up
32: wall to the right
64: wall to the down
128: wall to the left
I promise there must be nine Connecting-sub-grids, and each contains nine girds.
 

Output
For each case, if there are Multiple Solutions or no solution just output "Multiple Solutions" or "No solution". Else output the exclusive solution.(as shown in the sample output)
 

Sample Input
  
  
3 144 18 112 208 80 25 54 144 48 135 38 147 80 121 128 97 130 32 137 32 160 144 114 167 208 0 32 192 100 160 160 208 96 183 192 101 209 80 39 192 86 48 136 80 114 152 48 226 144 112 160 160 149 48 128 0 112 166 215 96 160 128 41 128 39 153 32 209 80 101 136 35 192 96 200 67 80 112 208 68 96 144 48 144 81 81 16 53 144 48 128 96 224 144 48 128 103 128 38 163 208 80 0 37 224 209 0 32 135 48 176 192 64 112 176 192 104 192 101 128 89 80 82 32 150 48 149 48 224 208 16 48 224 192 33 128 0 114 176 135 0 80 112 169 137 32 148 32 192 96 176 144 32 192 96 193 64 80 80 96 192 96 144 88 48 217 16 16 80 112 176 224 176 129 48 128 40 208 16 37 145 32 128 96 196 96 176 136 32 192 32 227 176 144 80 96 192 32 176 192 80 98 160 145 80 48 224 128 48 144 80 96 224 183 128 48 128 36 224 144 51 144 32 128 105 131 64 112 136 32 192 36 224 176 224 208 80 64 64 116 192 83 96
 

Sample Output
  
  
Case 1: 521439678 763895124 984527361 346182795 157964832 812743956 235678419 479216583 698351247 Case 2: No solution Case 3: Multiple Solutions
 

Source
 

Recommend
lcy



奇形怪状的数独

但是本质不变

数独题的解法参见POJ_3074_Sudoku(DancingLinksX精确覆盖)

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


就是小九宫的位置变成了给定的形状

先求出所有墙的位置以及原先的数字矩阵

用bfs求出各个区域,并为它们标号

代替原先的小九宫矩阵即可

另外这题需要求多解的情况 因此不能在得出一解的时候就跳出

因此ans数组可能保存的不是答案,需要特别注意


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

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

int ti[M+5][M+5]; //原始的数组以及后来的纯数字数组
int wall[M+5][M+5][4];//是否有墙
int id[M+5][M+5]; //对应的块
int an[MN];//答案数组,多次dance需要特别拿出来

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;
    }
    void dance(int d) //选取了d行
    {
        if(ansd>1)
            return;
        if(R[0]==0)//全部覆盖了
        {
            //全覆盖了之后的操作
            ansd++;
            if(ansd==1)
            {
                an[0]=d;
                for(int i=0;i<d;i++)
                    an[i+1]=ans[i];
            }
            return;
        }
        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]);
            dance(d+1);
            for(int j=L[i];j!=i;j=L[j])
                resume(Col[j]);
        }
        resume(c);
        return;
    }
    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*2+j*M+k;
        c4=M*M*3+id[i][j]*M+k;
    }
}dlx;

int dx[]={0,0,-1,1};
int dy[]={-1,1,0,0};
queue<int> qu;
void bfs(int st,int &nid)
{
    while(!qu.empty())
        qu.pop();
    qu.push(st);
    id[st/M][st%M]=nid;
    while(!qu.empty())
    {
        int t=qu.front();
        qu.pop();
        int tx=t/M,ty=t%M;
        for(int i=0;i<4;i++)
        {
            int x=tx+dx[i],y=ty+dy[i];
            if(wall[tx][ty][i]||id[x][y]!=-1)
                continue;
            id[x][y]=nid;
            qu.push(x*M+y);
        }
    }
    nid++;
}

int main()
{
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
    int t;
    scanf("%d",&t);
    for(int ca=1;ca<=t;ca++)
    {
        for(int i=0;i<M;i++)
            for(int j=0;j<M;j++)
                scanf("%d",&ti[i][j]);
        dlx.init(M*M*M,M*M*4);
        memset(wall,0,sizeof(wall));
        for(int i=0;i<M;i++)
            for(int j=0;j<M;j++)
            {
                if(ti[i][j]>=128)//左墙
                    ti[i][j]-=128,wall[i][j][0]=1;
                if(ti[i][j]>=64)//下墙
                    ti[i][j]-=64,wall[i][j][3]=1;
                if(ti[i][j]>=32)//右墙
                    ti[i][j]-=32,wall[i][j][1]=1;
                if(ti[i][j]>=16)//上墙
                    ti[i][j]-=16,wall[i][j][2]=1;
            }
        memset(id,-1,sizeof(id));
        int nid=0;
        for(int i=0;i<M;i++)
            for(int j=0;j<M;j++)
                if(id[i][j]==-1)
                    bfs(i*M+j,nid);
        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(ti[i][j]==0||ti[i][j]==k)
					{
						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.ansd=0;
        dlx.dance(0);
        printf("Case %d:\n",ca);
        if(dlx.ansd==0)
            printf("No solution\n");
        else if(dlx.ansd>1)
            printf("Multiple Solutions\n");
        else
        {
            int v,x,y;
            for(int i=1;i<=an[0];i++)
            {
                v=(an[i]-1)%M;
                x=(an[i]-1)/M/M;
                y=(an[i]-1)/M%M;
                ti[x][y]=v+1;
            }
            for(int i=0;i<M;i++)
            {
                for(int j=0;j<M;j++)
                    printf("%d",ti[i][j]);
                printf("\n");
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值