题目分析:16个字母的数独。精确覆盖问题。注意输出,两组输出之间空一行。
代码如下:
#include <bits/stdc++.h>
using namespace std ;
#define rec( i , A , o ) for ( int i = A[o] ; i != o ; i = A[i] )
#define clr( a , x ) memset ( a , x , sizeof a )
const int MAXC = 11000 ;//1024
const int MAXR = 41000 ;//4096
const int MAXNODE = 180000 ;//16384 + 1025
struct DLX {
int U[MAXNODE] , D[MAXNODE] , L[MAXNODE] , R[MAXNODE] ;
int row[MAXNODE] , col[MAXNODE] ;
int H[MAXR] , S[MAXC] ;
int size ;
int deep ;
int ans[MAXC] ;
int nv ;
char G[16][20] ;
void init ( int n ) {
nv = n ;
clr ( H , -1 ) ;
for ( int i = 0 ; i <= nv ; ++ i ) {
S[i] = 0 ;
U[i] = i ;
D[i] = i ;
L[i] = i - 1 ;
R[i] = i + 1 ;
}
L[0] = nv ;
R[nv] = 0 ;
size = nv ;
}
void link ( int r , int c ) {
++ size ;
++ S[c] ;
row[size] = r ;
col[size] = c ;
U[size] = U[c] ;
D[size] = c ;
D[U[c]] = size ;
U[c] = size ;
if ( ~H[r] ) {
L[size] = L[H[r]] ;
R[size] = H[r] ;
L[R[size]] = size ;
R[L[size]] = size ;
} else H[r] = L[size] = R[size] = size ;
}
void remove ( int c ) {
L[R[c]] = L[c] ;
R[L[c]] = R[c] ;
rec ( i , D , c ) rec ( j , R , i ) {
U[D[j]] = U[j] ;
D[U[j]] = D[j] ;
-- S[col[j]] ;
}
}
void resume ( int c ) {
rec ( i , U , c ) rec ( j , L , i ) {
++ S[col[j]] ;
D[U[j]] = j ;
U[D[j]] = j ;
}
R[L[c]] = c ;
L[R[c]] = c ;
}
int dance ( int d ) {
if ( R[0] == 0 ) {
deep = d ;
return 1 ;
}
int c = R[0] ;
rec ( i , R , 0 ) if ( S[c] > S[i] ) c = i ;
remove ( c ) ;
rec ( i , D , c ) {
ans[d] = row[i] ;
rec ( j , R , i ) remove ( col[j] ) ;
if ( dance ( d + 1 ) ) return 1 ;
rec ( j , L , i ) resume ( col[j] ) ;
}
resume ( c ) ;
return 0 ;
}
int solve ( int flag ) {
init ( 1 << 10 ) ;
for ( int i = 0 ; i < 16 ; ++ i ) {
if ( scanf ( "%s" , G[i] ) == EOF ) return 0 ;
for ( int j = 0 ; j < 16 ; ++ j ) if ( G[i][j] != '-' ) {
G[i][j] -= 'A' - 1 ;
int r = ( i * 16 + j ) * 16 + G[i][j] ;
int c1 = i * 16 + j + 1 ;
int c2 = 256 + i * 16 + G[i][j] ;
int c3 = 512 + j * 16 + G[i][j] ;
int c4 = 768 + ( i / 4 * 4 + j / 4 ) * 16 + G[i][j] ;
link ( r , c1 ) ;
link ( r , c2 ) ;
link ( r , c3 ) ;
link ( r , c4 ) ;
S[c1] = S[c2] = S[c3] = S[c4] = -1 ;
}
}
for ( int i = 0 ; i < 16 ; ++ i ) {
for ( int j = 0 ; j < 16 ; ++ j ) if ( G[i][j] == '-' ) {
for ( int k = 0 ; k < 16 ; ++ k ) {
int r = ( i * 16 + j ) * 16 + k + 1 ;
int c1 = i * 16 + j + 1 ;
int c2 = 256 + i * 16 + k + 1 ;
int c3 = 512 + j * 16 + k + 1 ;
int c4 = 768 + ( i / 4 * 4 + j / 4 ) * 16 + k + 1 ;
if ( ~S[c1] && ~S[c2] && ~S[c3] && ~S[c4] ) {
link ( r , c1 ) ;
link ( r , c2 ) ;
link ( r , c3 ) ;
link ( r , c4 ) ;
}
}
}
}
dance ( 0 ) ;
for ( int i = 0 ; i < deep ; ++ i ) {
int x = ( ans[i] - 1 ) % 16 + 'A' ;
int r = ( ans[i] - 1 ) / 16 / 16 ;
int c = ( ans[i] - 1 ) / 16 % 16 ;
G[r][c] = x ;
}
if ( flag ) printf ( "\n" ) ;
for ( int i = 0 ; i < 16 ; ++ i ) {
for ( int j = 0 ; j < 16 ; ++ j ) printf ( "%c" , G[i][j] ) ;
printf ( "\n" ) ;
}
return 1 ;
}
} x ;
int main () {
int flag = 0 ;
while ( x.solve ( flag ) ) flag = 1 ;
return 0 ;
}
本文介绍了一种使用精确覆盖问题求解16个字母的数独问题的方法,并提供了详细的C++实现代码。该算法通过回溯搜索来找出所有可能的解决方案。

496

被折叠的 条评论
为什么被折叠?



