传送门:【HUST】1017 Exact cover
题目分析:Dancing Links 模板题!终于学会了入门的Dancing Links了~~
这个算法依赖的是Knuth的舞蹈链——双向十字链表,通过这种数据结构我们可以做到快速的删除和恢复。
具体细节可以看看这篇文章,既然已经有人很好的总结了,那么我就不多说了> <
链接:跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题
代码如下:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std ; #define REP( i , a , b ) for ( int i = a ; i < b ; ++ i ) #define REV( i , a , b ) fot ( int i = a - 1 ; i >= b ; -- i ) #define FOR( i , a , b ) for ( int i = a ; i <= b ; ++ i ) #define FOV( i , a , b ) for ( int i = a ; i >= b ; -- i ) #define CLR( a , x ) memset ( a , x , sizeof a ) #define CC( i , A , s ) for ( int i = A[s] ; i != s ; i = A[i] ) const int MAXN = 1005 ; const int MAXNODE = 1280000 ; struct DLX { int L[MAXNODE] , R[MAXNODE] , U[MAXNODE] , D[MAXNODE] ; int row[MAXNODE] , col[MAXNODE] ;//元素对应的行列 int S[MAXN] , H[MAXN] ;//S记录该列剩余1的个数,H表示该行最左端的1 int ans_deep , ans[MAXN] ;//解的深度以及解答栈 int size ;//节点数 int n , m ;//行数,列数 void Link ( int r , int c ) {//新建节点 ++ size ; col[size] = c ; row[size] = r ; ++ S[c] ; U[size] = U[c] ; D[size] = c ; D[U[c]] = size ; U[c] = size ; if ( ~H[r] ) { R[size] = H[r] ; L[size] = L[H[r]] ; R[L[size]] = size ; L[R[size]] = size ; } else H[r] = L[size] = R[size] = size ; } void init () {//初始化 FOR ( i , 0 , m ) { S[i] = 0 ; U[i] = D[i] = i ; L[i] = i - 1 ; R[i] = i + 1 ; } R[m] = 0 ; L[0] = m ; size = m ; CLR ( H , -1 ) ; } void remove ( int c ) {//删除列 L[R[c]] = L[c] ; R[L[c]] = R[c] ; CC ( i , D , c ) CC ( j , R , i ) { U[D[j]] = U[j] ; D[U[j]] = D[j] ; -- S[col[j]] ; } } void resume ( int c ) {//恢复列 CC ( i , U , c ) CC ( j , L , i ) { ++ S[col[j]] ; U[D[j]] = j ; D[U[j]] = j ; } L[R[c]] = c ; R[L[c]] = c ; } int dance ( int d ) { if ( R[0] == 0 ) { ans_deep = d ; return 1 ; } int c = R[0] ; CC ( i , R , 0 ) if ( S[i] < S[c] ) c = i ; remove ( c ) ; CC ( i , D , c ) { ans[d] = row[i] ; CC ( j , R , i ) remove ( col[j] ) ; if ( dance ( d + 1 ) ) return 1 ; CC ( j , L , i ) resume ( col[j] ) ; } resume ( c ) ; return 0 ; } void input () { int t , j ; FOR ( i , 1 , n ) { scanf ( "%d" , &t ) ; while ( t -- ) { scanf ( "%d" , &j ) ; Link ( i , j ) ; } } } void solve () { init () ; input () ; if ( !dance ( 0 ) ) printf ( "NO\n" ) ; else { printf ( "%d" , ans_deep ) ; REP ( i , 0 , ans_deep ) printf ( " %d" , ans[i] ) ; puts ( "" ) ; } } } dlx ; int main () { while ( ~scanf ( "%d%d" , &dlx.n , &dlx.m ) ) dlx.solve () ; return 0 ; }