https://vjudge.net/problem/UVA-11212
题意:
n个数的排列,每次操作可以移动连续的一段
最问少移动多少次使这n个数升序排列
IDA*
估价函数:
考虑后即不正确的数字个数sum
每次移动最多使sum减少3
所以如果剩余递归层数*3<sum ,剪枝
#include<cstdio> #include<cstring> using namespace std; int n,T,maxd; bool stop; bool check(int *a) { bool p=true; for(int i=1;i<=n;i++) if(a[i]!=i) { p=false; break; } return p; } void dfs(int now,int *a) { if(stop) return; if(now==maxd+1) { if(check(a)) stop=true; return; } int sum=0; for(int i=1;i<n;i++) if(a[i+1]!=a[i]+1) sum++; if((maxd-now+1)*3<sum) return; int tmp[10]; memcpy(tmp,a,sizeof(*tmp)*(n+1)); for(int len=1;len<n;len++) for(int s=2;s+len-1<=n;s++) for(int pos=1;pos<s;pos++) { for(int i=1;i<=len;i++) a[pos+i-1]=tmp[s+i-1]; for(int i=pos,j=1;i<s;i++,j++) a[pos+len-1+j]=tmp[i]; dfs(now+1,a); memcpy(a,tmp,sizeof(*a)*(n+1)); } } int main() { int a[10]; while(scanf("%d",&n)==1) { if(!n) return 0; T++; bool ok=true; stop=false; for(int i=1;i<=n;i++) { scanf("%d",&a[i]); if(a[i]<a[i-1]) ok=false; } if(ok) { printf("Case %d: 0 ",T); continue; } for(maxd=1;maxd<=n;maxd++) { dfs(1,a); if(stop) { printf("Case %d: %d ",T,maxd); break; } } } }