hdu 1426 Sudoku Killer ( Dancing Link 精確覆蓋 ),hdusudoku

來源:互聯網
上載者:User

hdu 1426 Sudoku Killer ( Dancing Link 精確覆蓋 ),hdusudoku

利用 Dancing Link 來解數獨

具體的可以看    lrj 的訓練指南 和 《 Dancing Links 在搜尋中的應用 》這篇論文


Dancing Link 來求解數獨 , 是通過求解精確覆蓋

精確覆蓋就是給出一個 01 矩陣 , 要求我們選擇一些行 , 使得每一列有且僅有一個 1


對於數獨問題 , 行就是我們的選擇 , 即在第 i 行 第 j 列 放上 數字 k , 所以我們最多有 i * j * k 中選擇

如果某些位置( x , y  )已經放了數字 a , 那麼我們的選擇只能是 ( x , y , a ) , 否則的話, 我們可以選擇 ( x , y , 1 ~ 9 )


對於列 , 也就是我們需要滿足的條件 , 這裡有 4 大類條件:

1. 第 x 行 第 y 列要有 數字

2. 第 x 行 要有 數字 y

3. 第 x 列 要有 數字 y

4. 第 x 個宮要有數字 y

所以總共有 9*9*4 列 ( 假設 9*9*4 的數獨的話 )


然後我們只要進行DLX就行了


#include <stdio.h>#include <string.h>#include <algorithm>#include <vector>using namespace std;const int maxn = 9 * 9 * 4 + 10 ;const int maxr = 9 * 9 * 9 + 10 ;const int maxnode = maxr * 4 + maxr + 10 ;#define FOR( i , A , s ) for( int i = A[s] ; i != s ; i = A[i] ) struct DLX{    // maxn 列數 , maxnode 總節點數 , maxr 行數    int n , sz ;    int S[maxn] ;     int row[maxnode] , col[maxnode] ;    int L[maxnode] , R[maxnode] , U[maxnode] , D[maxnode] ;    int H[maxr] ;    int ansd , ans[maxr] ;    void init( int N ) {        n = N ;        // 第一行的虛擬結點        for( int i = 0 ; i <= n ; i ++ ) {            U[i] = D[i] = i ;            L[i] = i - 1 ;             R[i] = i + 1 ;        }        R[n] = 0 ; L[0] = n ;        sz = n + 1 ;// 每一列的個數        memset( S , 0 , sizeof(S) ) ;// H[i] = -1 表示這一行還沒有 1 // 否則表示第一個 1 的 sz 是多少        memset( H , -1 , sizeof(H)) ;    }    // 在第r行第c列添加一個1    void Link( int r , int c ) {        row[sz] = r ;        col[sz] = c ;        S[c] ++ ;        D[sz] = c ; U[sz] = U[c] ;        D[U[c]] = sz ; U[c] = sz ;        if( H[r] < 0 ) { H[r] = L[sz] = R[sz] = sz ; }        else{            R[sz] = H[r] ;            L[sz] = L[H[r]] ;            R[L[sz]] = sz ;            L[R[sz]] = sz ;        }        sz ++ ;    }    // 刪除 第 c 列    void remove ( int c ) {        // 刪除虛擬結點中的 c 列        L[R[c]] = L[c] ;        R[L[c]] = R[c] ;        // 從 c 列向下遍曆        FOR( i , D , c ) {            // 刪除遍曆到的行            FOR( j , R , i ) {                D[U[j]] = D[j] ;                U[D[j]] = U[j] ;                -- S[col[j]] ;            }        }    }    // 恢複第 c 列    void restore( int c ) {        FOR( i , U , c ) {            FOR( j , L , i ) {                ++S[col[j]] ;                U[D[j]] = D[U[j]] = j ;            }        }        L[R[c]] = R[L[c]] = c ;    }    bool dfs( int d ) {// 如果已經沒有列了 , 演算法結束        if( R[0] == 0 ) {            ansd = d ;            return true ;        }        // 找到 s 最小的列 , 加快搜尋的速度        int c = R[0] ;        FOR( i , R , 0 ) {            if( S[i] < S[c] ) c = i ;        }        // 刪除第 c 列        remove( c ) ;// 遍曆選中列中有1的行        FOR( i , D , c ) {            ans[d] = row[i] ;// 刪除選中行中有1的列            FOR( j , R , i ) {                remove( col[j] ) ;            }            if( dfs( d + 1 ) ) return true ;// 回複刪除掉的列            FOR( j , L , i ) {                restore( col[j] ) ;            }        }        restore( c ) ;        return false ;    }    bool solve() {        if( !dfs(0) ) return false ;        return true ;    }} dlx ;int ans[15][15] ;const int SLOT = 0 ;const int ROW  = 1 ;const int COL  = 2 ;const int SUB  = 3 ;inline int encode (  int a , int b , int c ) {    return a * 9 * 9 + b * 9 + c + 1 ;}int main(){    char str[5] ;    int casn =  0 ;    while( scanf( "%s" , str ) != EOF ) {        if( str[0] == '?' ) {            ans[0][0] = 0 ;        }else{            ans[0][0] = str[0] - '0' ;        }        for( int i = 0 ; i < 9 ; i ++ ) {            for( int j = 0 ; j < 9 ; j ++ ) {                if( i == 0 && j == 0 ) continue ;                scanf( "%s" , str ) ;                if( str[0] == '?' )                     ans[i][j] = 0 ;                else                    ans[i][j] = str[0] - '0' ;            }        }        if( casn ++ ) {            puts( "" ) ;        }        dlx.init( 9 * 9 * 4 ) ;        for( int i = 0 ; i < 9 ; i ++ ) {            for( int j = 0 ; j < 9 ; j ++ ) {                for( int k = 0 ; k < 9 ; k ++ ) {                    int rr = encode( i , j , k ) ;                    if( ans[i][j] == 0 || ans[i][j] == k + 1 ) {                        dlx.Link( rr , encode( SLOT , i , j ) ) ;                        dlx.Link( rr , encode( ROW  , i , k ) ) ;                        dlx.Link( rr , encode( COL  , j , k ) ) ;                        dlx.Link( rr , encode( SUB  , ( i / 3 ) * 3 + j / 3 , k ) ) ;                                            }                }            }         }        dlx.solve() ;        for( int i = 0 ; i < dlx.ansd ; i ++ ) {            int r , c , v ;            int t = dlx.ans[i] ;            t -- ;            v = t % 9 ;            t /= 9 ;            c = t % 9 ;            t /= 9 ;            r = t ;            ans[r][c] = v + 1 ;        }        for( int i = 0 ; i < 9 ; i ++ ) {            for( int j = 0 ; j < 9 ; j ++ ) {                printf( j == 8 ?"%d\n" : "%d " , ans[i][j] ) ;            }        }    }    return 0 ;}






聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.