AcWing 180. 排书
打死本蒟蒻也想不到的估价函数
考察:IDA*
知道初态和终态,明显可以用双向搜索.时间复杂度是O(15*15*15)5/2 计算出来是>1e9,但实际底数没有15*15*15那么大.第一个是枚举长度,第二个枚举左端点,第三个枚举要放的位置.可能可以压线过.这里主要讲IDA*解法,代码跑的时间是141ms
思路:
IDA*算法是A*算法与迭代加深的结合.这里明显可以用迭代加深,难点主要在估价函数怎么想.
终态的每个数比后一个数<1,我们每次将区间挪动,都可以改变3个位置的相邻数关系.可以计算初态相邻数关系不是终态关系的数量,那么估价函数的步数就是(tot+2)/3.
即使只改变2个元素的关系也没关系,上取整使得预估函数返回1而并非0(所以一定不能用下取整)
还有一个较难的是移动数组位置,我们需要备份数组.先将[r+1,k]的元素往前挪,再将[l,r]区间的元素赋值到目标位置.
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 const int N = 16; 6 int a[N],n,depth,b[5][N]; 7 int h() 8 { 9 int res = 0; 10 for(int i=1;i<n;i++) 11 if(a[i+1]-a[i]!=1) res++; 12 return (res+2)/3; 13 } 14 bool dfs(int step) 15 { 16 int val = h(); 17 if(step+val>depth) return 0; 18 if(!val) return 1; 19 for(int len=1;len<=n;len++) 20 for(int l=1;l+len-1<n;l++) 21 { 22 int r = l+len-1; 23 for(int k=r;k<=n;k++) 24 { 25 memcpy(b[step],a,sizeof a); 26 int j = l; 27 for(int i=r+1;i<=k;i++,j++) a[j] = a[i]; 28 for(int i=l;i<=r;i++,j++) a[j] = b[step][i]; 29 if(dfs(step+1)) return 1; 30 memcpy(a,b[step],sizeof a); 31 } 32 } 33 return 0; 34 } 35 int main() 36 { 37 int T; 38 scanf("%d",&T); 39 while(T--) 40 { 41 scanf("%d",&n); 42 depth = 0; 43 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 44 while(depth<5&&!dfs(0)) depth++; 45 if(depth>=5) puts("5 or more"); 46 else printf("%d\n",depth); 47 } 48 return 0; 49 }