https://hihocoder.com/problemset/problem/1233
题意:有很多个大小不同的盒子,排成一排,可以类似汉诺塔一样的移动他们,每次只能移动每个位置最顶上的那个盒子,只能移动到和他相邻的位置上去,并且是小盒子只能放在大盒子上面,问最后把这些盒子排成一个大小从小到大的顺序,需要的最少的次数,如果不可以,输出-1
想到是状态压缩从终点往回BFS预处理,但想歪了压缩的思路,想法是按位置所有的盒子状态压缩,这样会有很多种不会出现的状态,
看了题解就懂了,按每个盒子所在的位置压缩,n个盒子就一个n进制数,每一位的值代表现在这个盒子在哪个位置上,当然每个位置上最小的值必然就是最顶上的盒子
还有一点也是想歪了。。。。以为不同盒子数量是无差别的,只需要预处理出7个盒子时,对于小数量固定前某部分就可以,其实并不,多了一个盒子数量等于多了一个可移动的位置
#include<bits/stdc++.h>
using namespace std;
int ans[8][3000005],fac[10],a[10];
struct node
{
int a,id;
}num[10];
int cmp(node u,node v)
{
return u.a<v.a;
}
int main()
{
memset(ans,-1,sizeof(ans));
int n,now=1,state=0,i,j;
//枚举有多少个盒子
for(n=1;n<=7;n++)
{
fac[0]=1;
for(i=1;i<n;i++)
{
fac[i]=fac[i-1]*n;
}
now=1,state=0;
queue<int>Q;
//终点状态值
for(i=0;i<n;i++)
{
state+=now*i;
now*=n;
}
ans[n][state]=0;
Q.push(state);
//BFS预处理所有可达状态的答案
while(!Q.empty())
{
now=Q.front();
Q.pop();
for(i=0;i<n;i++)
{
a[i]=n;
}
state=now;
for(i=0;i<n;i++)
{
int temp=state%n;
if(a[temp]==n)
a[temp]=i;
state/=n;
}
for(i=0;i<n;i++)
{
if(i!=0)
{
if(a[i]<n&&a[i]<a[i-1])
{
state=now-fac[a[i]];
if(ans[n][state]==-1)
{
ans[n][state]=ans[n][now]+1;
Q.push(state);
}
}
}
if(i!=n-1)
{
if(a[i]<n&&a[i]<a[i+1])
{
state=now+fac[a[i]];
if(ans[n][state]==-1)
{
ans[n][state]=ans[n][now]+1;
Q.push(state);
}
}
}
}
}
}
int T;
cin>>T;
while(T--)
{
state=0;
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d",&num[i].a);
num[i].id=i;
}
sort(num,num+n,cmp);
now=1;
//压缩成状态值
for(i=0;i<n;i++)
{
state+=now*num[i].id;
now*=n;
}
printf("%d\n",ans[n][state]);
}
return 0;
}