题目链接:
http://hihocoder.com/problemset/problem/1233
解题思路:
题目大意:
有n个卡槽,放有体积不同的n个空盒子,每次你可以移动一个空盒子到相邻卡槽,但前提是相邻卡槽若已经有空盒子,那么要移动
的空盒子体积必须小于已有的空盒子,问要移动多少步才能使得从左到右,每个卡槽空盒子的体积递增。
解题思路:
说实话,不得不佩服网上的一些大牛们,自己以前学的状态压缩这是渣渣,
http://blog.csdn.net/u014664226/article/details/48615393看了他的博客后,我才知道,状态压缩说
的很简单,把状态压缩,但是实际操作起来,脑洞真是要够大的呀。。。他是说的:用每个盘子所在的位置表示状态,每个盘子的
位置用三位二进制表示,总共的状态为2^21,因为每次盘子只能向左放或者向右放,那么我们从结束的位置开始搜索,bfs预处理出
目标状态到所有状态所需要的最小步数,然后对于每个询问O(1)回答即可。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn = 5000000;
int n;
int a[10],b[10];
int vis[maxn];
bool tmp[10];
void bfs(int n){
queue<int> q;
int cur = 0;
for(int i = 0; i < n; i++)
cur += (i+1) * (1 << (3*i));
q.push(cur);
vis[cur] = 0;
while(!q.empty()){
cur = q.front();
q.pop();
memset(tmp,0,sizeof(tmp));
for(int i = 0; i < n; i++){//i+1在哪个位置
int pos = (cur >> (3*i)) % 8;
if(tmp[pos])
continue;
tmp[pos] = 1;
if(pos>1 && !tmp[pos-1]){
int t = cur - (1<<(3*i));
if(vis[t] == -1){
q.push(t);
vis[t] = vis[cur] + 1;
}
}
if(pos<n && !tmp[pos+1]){
int t = cur + (1<<(3*i));
if(vis[t] == -1){
q.push(t);
vis[t] = vis[cur] + 1;
}
}
}
}
}
int main(){
int T;
scanf("%d",&T);
memset(vis,-1,sizeof(vis));
for(int i = 1; i <= 7; i++)
bfs(i);
while(T--){
scanf("%d", &n);
for(int i = 1; i <= n; i++){
scanf("%d",&a[i]);
b[i] = a[i];
}
sort(b+1, b+n+1);
for(int i = 1; i <= n; i++)
a[i] = lower_bound(b+1,b+n+1,a[i]) - b - 1;
int s = 0;
for(int i = 1; i <= n; i++)
s += i*(1<<(3*a[i]));
printf("%d\n",vis[s]);
}
return 0;
}