大致就是给一个1到n的数字组成的乱序数组,问最少剪贴黏贴几次能把它变成一个1到n升序的数组。
用IDA* 不正确的数字个数为h 则每个深度h最多减少3(后接数字变化的三个数都对上,减少三) 则3d+h>3maxd就剪枝(当前操作方法减少的不正确数超过最多不正确数)
这道题枚举剪切黏贴的方法很值得学习
AC代码:
/*#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int n,a[10];
bool ans_sort()
{
for(int i=0;i<n-1;i++)
if(a[i]>=a[i+1]) return false;
return true;
}
int h()
{
int cnt=0;
for(int i=0;i<n-1;i++)
if(a[i]+1!=a[i+1]) cnt++;
if(a[n-1]!=n)cnt++;
return cnt;
}
bool dfs(int d,int maxd)
{
if(d*3+h()>=maxd*3) return false;
if(ans_sort()) return true;
int o[10],b[10];
memcpy(o,a,sizeof(a));
for(int i=0;i<n;i++)
{
for(int j=i;j<n;j++)
{
int cnt=0;
for(int k=0;k<n;k++)
if(k<i||k>j)b[cnt++]=a[k];
for(int k=0;k<=cnt;k++)
{
int cnt2=0;
for(int p=0;p<k;p++) b[cnt2++]=b[p];
for(int p=i;p<=j;p++)a[cnt2++]=o[p];
for(int p=k;p<cnt;p++)a[cnt2++]=b[p];
if (dfs(d+1,maxd)) return true;
memcpy(a,o,sizeof(a));
}
}
}
return false;
}
int solve()
{
int max_ans=8;
for(int maxd=1;maxd<8;maxd++)
if(dfs(0,maxd))return maxd;
return max_ans;
}
int main()
{
int kase=0;
while(cin>>n&&n)
{
for(int i=0;i<n;i++) cin>>a[i];
printf("Case %d: %d\n",++kase,solve()-1);
}
return 0;
}
*/
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int a[10],n,maxd;
int h()
{
int cnt=0;
for(int i=0;i<n-1;i++)
if(a[i]+1!=a[i+1])cnt++;
if(a[n-1]!=n) cnt++;
return cnt;
}
bool dfs(int d)
{
int cnt=h();
if(d*3+cnt>maxd*3) return false;
if(!cnt) return true;
int b[10],c[10];
memcpy(b,a,sizeof(a));
for(int i=0;i<n;i++)
{
for(int j=i;j<n;j++)
{
int cnt1=j-i+1,cnt2=n-cnt1;
memcpy(c,b,sizeof(int)*i);
memcpy(c+i,b+j+1,sizeof(int)*(n-j));
for(int k=0;k<=cnt2;k++)
{
if(i==k) continue;
memcpy(a,c,sizeof(int)*k);
memcpy(a+k,b+i,sizeof(int)*cnt1);
memcpy(a+k+cnt1,c+k,sizeof(int)*(n-cnt1-k));
if(dfs(d+1)) return true;
}
}
}
memcpy(a,b,sizeof(a));
return false;
}
int main()
{
int kase=0;
while(cin>>n&&n)
{
for(int i=0;i<n;i++) cin>>a[i];
for(maxd=0;maxd<9;maxd++)
if(dfs(0)) break;
printf("Case %d: %d\n",++kase,maxd);
}
return 0;
}