题目链接:http://poj.org/problem?id=3460
题意:有一些高度不等的书,可以一次取出一摞相对顺序不变的书插入任意位置,问最少多少次操作才能使书的高度递增有序。
IDA*,刘汝佳黑书P169的例题,经典题目,启发函数的设计十分巧妙。
以“h(s)=后继书本高度正确的书本个数”为估价函数,假设每次把一摞书本S从P1后面移动到P2后面,只有P1,S1的最后一本,P2三本书的后继有变化,h每次最多减少3,令h'=h(s)/3作为估价函数值,则每次h最多减少1。
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 6 const int MAXN = 20; 7 8 int N, limit; 9 int book[MAXN]; 10 bool find; 11 12 int min( int a, int b ) 13 { 14 return a < b ? a : b; 15 } 16 17 int h( int *a ) 18 { 19 int cnt = 0; 20 if ( a[0] != 1 ) ++cnt; 21 if ( a[N - 1] != N ) ++cnt; 22 for ( int i = 1; i < N - 1; ++i ) 23 if ( a[i] + 1 != a[i + 1] ) ++cnt; 24 return ceil( cnt / 3.0 ); 25 } 26 27 void chuli( int st, int mid, int ed ) 28 { 29 int temp[MAXN]; 30 for ( int i = mid + 1; i <= ed; ++i ) 31 temp[i] = book[i]; 32 for ( int i = mid, j = ed; i >= st; --i, --j ) 33 book[j] = book[i]; 34 for ( int i = st, j = mid + 1; j <= ed; ++i, ++j ) 35 book[i] = temp[j]; 36 return; 37 } 38 39 int DFS( int dv ) 40 { 41 int temp[MAXN]; 42 int hv = h( book ); 43 if ( hv + dv > limit ) return hv + dv; 44 if ( hv == 0 ) 45 { 46 find = true; 47 return dv; 48 } 49 50 int next_limit = 1e5; 51 52 for ( int i = 0; i < N - 1; ++i ) 53 for ( int j = i + 1; j < N; ++j ) 54 for ( int k = i; k < j; ++k ) 55 { 56 for ( int x = 0; x < N; ++x ) 57 temp[x] = book[x]; 58 59 chuli( i, k, j ); 60 61 int new_limit = DFS( dv + 1 ); 62 63 if ( find ) return new_limit; 64 65 next_limit = min( next_limit, new_limit ); 66 for ( int x = 0; x < N; ++x ) 67 book[x] = temp[x]; 68 } 69 70 return next_limit; 71 } 72 73 void IDA_Star() 74 { 75 find = false; 76 limit = h( book ); 77 while ( !find && limit < 5 ) 78 limit = DFS( 0 ); 79 return; 80 } 81 82 int main() 83 { 84 int T; 85 scanf( "%d", &T ); 86 while ( T-- ) 87 { 88 scanf( "%d", &N ); 89 for ( int i = 0; i < N; ++i ) 90 scanf( "%d", &book[i] ); 91 92 IDA_Star(); 93 if ( find ) printf( "%d\n", limit ); 94 else puts("5 or more"); 95 } 96 return 0; 97 }