题意:有n个卡槽,放有体积不同的n个空盒子,每次你可以移动一个空盒子到相邻卡槽,但前提是相邻卡槽若已经有空盒子,那么要移动的空盒子体积必须小于已有的空盒子,问要移动多少步才能使得从左到右,每个卡槽空盒子的体积递增。
思路:就是搜索,但是需要想出一种办法来表示当前搜索的状态。一开始我自己想的时候是想每个位置给他来个n位的二进制,来记录这个位置上面有哪几个盒子,但是想了想这样记录是不太好做的,每种状态就要用n个数字去记录,还要从每个位置上找到体积最小的那个盒子,很不好弄,就放弃了。比赛过程中学长给我草草说了一边一个方法,但是没听懂。今天补题的时候又问了问才弄明白是怎么一回事。因为n的大小不确定,但是最后得到的盒子体积都是升序排列,所以就可以从最后的序列搜到每种排列状态,这样做到预处理一遍,记录下来,然后查询O(1)。
那么问题是如何记录当前的状态呢?因为就7个位置么,所以可以用3位二进制数来表示第i个盒子的在哪个位置,这些盒子的位置可以汇总到一起,用最多21位二进制数表示一个状态,这样状态就相较于我之前的想法好表示的很多,也易操作了许多。我们用pos[i]表示升序排列的第i个盒子当下处在哪个位置,比如说12345是升序排列,43251是一种情况,那么升序排列的第1个盒子位于43251的第5个位置,那么我们将pos[i]压缩成一个数
for(int i=0;i<n;i++) {code=code|(pos[i]<<(i*3));}
表示当下状态中升序排列的每一个盒子所处的位置。然后我们还需要一个fis数组,来记录当前状态下每个位置的最小体积的盒子的编号,我们需要用fis数组来进行盒子的挪动,同时改变挪动盒子的pos,然后进行bfs。上面提到的第i个盒子所处的位置,每个位置的最小体积合资的编号呀都是升序排列中的盒子编号,因为升序排列中的盒子编号与其体积大小对应,所以省去了记录盒子体积的操作。
原本不想贴代码了,因为不是我写的,但是怕以后自己光看原理看不懂就把代码一起贴上了。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <set>
#include <queue>
#include <algorithm>
#include <cmath>
#define cl(a,b) memset(a,b,sizeof(a))
#define maxn 0x77777777
using namespace std;
int da[8];
int res[2200100];
int pos[8];
int fis[8];
typedef struct data
{
int pos,rs;
}D;
D dat[9];
int cmpp(D a,D b)
{
return a.pos<b.pos;
}
int cmpr(D a,D b)
{
return a.rs<b.rs;
}
void decode(int code,int cn)
{
int i,j;
for(i=0;i<cn;i++)
{
pos[i]=code&7;///
code=code>>3;
}
cl(fis,0x77);
for(i=0;i<cn;i++)
{
fis[pos[i]]=min(fis[pos[i]],i+1);///
}
}
int tocode(int cn)///yasuo
{
int code=0;
for(int i=0;i<cn;i++)
{
code=code|(pos[i]<<(i*3));
}
return code;
}
void bfs(int cn)
{
queue<int> que;
int code=0,i,j,k,np,po,f;
for(i=0;i<cn;i++)
{
code=code|((i+1)<<(3*i));///
}
que.push(code);
res[code]=0;
while(!que.empty())
{
f=que.front();
que.pop();
decode(f,cn);
for(i=0;i<cn;i++)
{
po=pos[i];
np=i+1;
if(fis[po]!=np)continue;
if(po!=1)
{
if(fis[po-1]>np)
{
pos[i]-=1;
code=tocode(cn);
if(res[code]==-1){
que.push(code);
res[code]=res[f]+1;
}
pos[i]+=1;
}
}
if(po!=cn)
{
if(fis[po+1]>np)
{
pos[i]+=1;
code=tocode(cn);
if(res[code]==-1){
que.push(code);
res[code]=res[f]+1;
}
pos[i]-=1;
}
}
}
}
}
int main()
{
cl(res,-1);
for(int i=1;i<8;i++){
bfs(i);
}
int tt,ii,cn,i,j,k,code;
cin>>tt;
while(tt--)
{
scanf("%d",&cn);
for(i=0;i<cn;i++)
{
scanf("%d",&dat[i].rs);
dat[i].pos=i+1;
}
sort(dat,dat+cn,cmpr);///
for(i=0;i<cn;i++)
{
pos[i]=dat[i].pos;///
}
code=tocode(cn);
printf("%d\n",res[code]);
}
return 0;
}