hdu4069 Squiggly Sudoku

        解一个9*9的数独,行和列和普通数独一样需要出现1~9,但是它的小区域不是方形的,而是一个不规则的面积为9的图形。

        DLX模版题。位运算和dfs处理小区域的边界就不说了。DLX搜解,搜到一个解以后继续搜,如果搜到第二个解则说明有多解,立即跳出。需要注意的是,搜到第一个解以后,需要保存解,不然继续搜索原来的解会被破坏。


#include <stdlib.h>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
using namespace std;   
  
#define ll long long  

const int SLOT = 0;
const int ROW = 1;
const int COL = 2;
const int SUB = 3;

int encode(int type,int id,int num){
    return type*81+(id-1)*9+num;
}

int mp[12][12];
int sub[12][12];

const int maxnode=270000;
const int maxn=350;
const int maxr=750;

int anscnt;
void init(){
    anscnt=0;
    memset(sub,0,sizeof(sub));
}

struct dlx{
	#define FOR(i,A,s) for(int i = A[s];i!=s;i=A[i])
    int n,sz;
    int U[maxnode],D[maxnode],L[maxnode],R[maxnode];
    int row[maxnode],col[maxnode];
    
    int S[maxn];    //各列节点数 
    int ans[maxr];
    int ans2[maxr];
    int ansdep;
    
    void init(int n){
        this->n=n;
        sz=0;
        memset(S,0,sizeof(S));
        
        for(int i=0;i<=n;i++){
            U[i]=D[i]=i;
            L[i]=i-1;    R[i]=i+1;
            sz++;
        }
        L[0]=n;    R[n]=0;
    }
    
    void addrow(int r,vector<int> newrow){
        int first=sz;
        for(int i=0;i<newrow.size();i++){
            int pos=newrow[i];
            U[sz]=U[pos];    D[sz]=pos;
            U[pos]=sz;
            D[U[sz]]=sz;
            row[sz]=r;
            col[sz]=pos;
            S[pos]++;
            sz++;
        
        }
        for(int i=first;i<sz;i++){
            L[i]=i-1;    R[i]=i+1;
        }
        L[first]=sz-1;    R[sz-1]=first;
    }
    
    void remove(int c){
        R[L[c]]=R[c];
        L[R[c]]=L[c];
        FOR(i,D,c){
            FOR(j,R,i){
                U[D[j]]=U[j];    D[U[j]]=D[j];
                --S[col[j]];
            }
        }
    }
    
    void restore(int c){
        FOR(i,U,c){
            FOR(j,L,i){
            	++S[col[j]];
                U[D[j]]=j;    D[U[j]]=j;
            }
        }
        R[L[c]]=c;
        L[R[c]]=c;
    }
    
    void dfs(int d){
        if(anscnt>1)return;
        if(R[0]==0){
            ansdep=d;
            anscnt++;
            memcpy(ans2,ans,sizeof(ans));
            return;
        }
        
        int c=R[0];    //去满足一列 
        for(int i=c;i!=0;i=R[i]){
            if(S[i]<S[c])c=i;
        }

        remove(c);
        FOR(i,D,c){    //遍历这一列 
            ans[d]=row[i];
            FOR(j,R,i){
                remove(col[j]);
            }
            dfs(d+1);
            FOR(j,L,i){
                restore(col[j]);
            }
        }
        restore(c);
    }
    
}solver;

void dfs(int nn,int mm,int val){
    //找上下左右
    //u16 r32 d64 l128
    if(sub[nn][mm])return;
    sub[nn][mm]=val;
    if( (mp[nn][mm]&16)==0){
        dfs(nn-1,mm,val);
    }
    if( (mp[nn][mm]&32)==0){
        dfs(nn,mm+1,val);
    }
    if( (mp[nn][mm]&64)==0){
        dfs(nn+1,mm,val);
    }
    if( (mp[nn][mm]&128)==0){
        dfs(nn,mm-1,val);
    }
    
}

int main(){

    int t;
    cin>>t;
    int cas=0;
    while(t--){
        init();    cas++;
        for(int i=1;i<=9;i++){
            for(int j=1;j<=9;j++){
                scanf("%d",&mp[i][j]);
            }
        }
        
        int subcnt=0;
        for(int i=1;i<=9;i++){
            for(int j=1;j<=9;j++){
                if(!sub[i][j]){
                    dfs(i,j,++subcnt);
                }
            }
        }
        //
        for(int i=1;i<=9;i++){
            for(int j=1;j<=9;j++){
                mp[i][j]&=15;
            }
        }
        
        solver.init(324);
        
        for(int i=1;i<=9;i++){
            for(int j=1;j<=9;j++){
                for(int k=1;k<=9;k++){
                    if(mp[i][j]==k||mp[i][j]==0){
                        vector<int> vec;
                        vec.push_back(encode(SLOT,i,j));
                        vec.push_back(encode(ROW,i,k));
                        vec.push_back(encode(COL,j,k));
                        vec.push_back(encode(SUB,sub[i][j],k));
                        solver.addrow( (i-1)*81+(j-1)*9+(k-1) ,vec);
                    }
                }
            }
        }
        
        solver.dfs(0);
        
        printf("Case %d:\n",cas);
        if(anscnt==0){
            printf("No solution\n");
        }else if(anscnt==1){
            for(int i=0;i<81;i++){
                int tmp=solver.ans2[i];
                int nn=tmp/81;
                tmp-=nn*81;
                int mm=tmp/9;
                int val=tmp%9;
                mp[nn+1][mm+1]=val+1;
            }
            for(int i=1;i<=9;i++){
                for(int j=1;j<=9;j++){
                    printf("%d",mp[i][j]);
                }printf("\n");
            }
        }else{
            printf("Multiple Solutions\n");
        }
    }
    return 0;
}



你可能感兴趣的:(dlx)