【题意】
有n个数字的全排列,每次可以剪切一段粘贴到某个位置。问最后变成升序最少多少步。
如“{2,4,1,5,3,6}要2步
{3,4,5,1,2}只要一步
【分析】
迭代深搜真的AC了也觉得慌= =
【其实看到这题不应该想到宽搜么???
全排列只有9!=362880个
这题的IDA*的估价函数特别机智:
n<=9,最多2需要8步,深度上限为8。
考虑后继不正确的赎回自个数h,可以证明每次剪切时候h最多减少3,因此当3*d+h>3*maxd时可以剪枝。
【证明上面那个画一下就知道,一次复制粘贴只有3个东西的后继被影响。【机智ORZ ....
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<queue> 7 #include<cmath> 8 using namespace std; 9 #define Maxn 15 10 11 int a[Maxn][Maxn],v[Maxn]; 12 int maxd,n; 13 bool ok; 14 15 bool ffind(int x,int h) 16 { 17 if(x==maxd) 18 { 19 if(h!=0) return 0; 20 ok=1;return 1; 21 } 22 if(3*x+h>3*maxd) return 0; 23 for(int i=1;i<=n;i++) 24 for(int j=i;j<=n;j++) 25 { 26 for(int k=1;k<i;k++) 27 { 28 for(int l=i;l<=j;l++) a[x+1][k+l-i]=a[x][l]; 29 for(int l=k;l<i;l++) a[x+1][l+j-i+1]=a[x][l]; 30 for(int l=1;l<k;l++) a[x+1][l]=a[x][l]; 31 for(int l=j+1;l<=n;l++) a[x+1][l]=a[x][l]; 32 h=0; 33 for(int l=1;l<n;l++) if(a[x+1][l+1]!=a[x+1][l]+1) h++; 34 35 ffind(x+1,h); 36 if(ok==1) return 1; 37 } 38 for(int k=j+1;k<=n;k++) 39 { 40 for(int l=i;l<=j;l++) a[x+1][k+l-j]=a[x][l]; 41 for(int l=1;l<i;l++) a[x+1][l]=a[x][l]; 42 for(int l=j+1;l<=k;l++) a[x+1][l-j+i-1]=a[x][l]; 43 for(int l=k+1;l<=n;l++) a[x+1][l]=a[x][l]; 44 h=0; 45 for(int l=1;l<n;l++) if(a[x+1][l+1]!=a[x+1][l]+1) h++; 46 ffind(x+1,h); 47 if(ok==1) return 1; 48 } 49 } 50 return 0; 51 } 52 53 int main() 54 { 55 int kase=0; 56 while(1) 57 { 58 ok=0; 59 scanf("%d",&n); 60 if(n==0) break; 61 for(int i=1;i<=n;i++) scanf("%d",&a[0][i]); 62 int h=0; 63 for(int i=1;i<n;i++) if(a[0][i+1]!=a[0][i]+1) h++; 64 printf("Case %d: ",++kase); 65 for(maxd=0;maxd<=n-1;maxd++) 66 { 67 if(ffind(0,h)) {printf("%d",maxd);break;} 68 } 69 printf(" "); 70 } 71 return 0; 72 }
2016-11-15 09:13:56