您的位置:首页 > 其它

HihoCoder 1233 Boxes (bfs 状压)

2017-10-07 17:26 351 查看
题意:有n个盒子放在n个放盒子的位置(1<=n<=7),每个盒子大小不一,每次可以将一个盒子往它相邻的位置移,但是只能把小的

盒子往没盒子的位置或大的盒子上移。求最小移动多少次后盒子能从小到大排列地放在每个位置(每个位置一个)(T<=6e3)

思路:因为n才7,所以容易想到状压。每个位置有3位二进制表示,所以一共需要2^21这么大的数组。状态表示第i个盒子所在的位

置。(因为盒子大小只与相对大小有关,所以一开始先将大小离散化成1-n)。因为T比较大,每次盒子只能向左放或者向右放,那

么我们从结束的位置开始搜索,bfs预处理出目标状态到所有状态所需要的最小步数,这样对于每个询问可以O(1)回答。

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e6+5;
int vis[maxn];
bool book[15];

void bfs(int n)
{
queue<int> q;
int tmp = 0;
for(int i = 0; i < n; i++)
tmp += (i+1)*(1<<(3*i));
q.push(tmp);
vis[tmp] = 0;
while(!q.empty())
{
int u = q.front(); q.pop();
memset(book, 0, sizeof(book));
for(int i = 0; i < n; i++) //枚举第i+1个盒子,注意是从小的开始枚举
{
int pos = (u>>(i*3))%8;//第i+1个盒子所在位置
if(book[pos]) continue; //表示这个盒子上有比它小的盒子,所以不能移
book[pos] = 1;
if(pos > 1 && !book[pos-1]) //要满足左边的盒子比他大,如果动过就代表比它小,不能移
{
int t = u-(1<<(3*i));
if(vis[t] == -1)
{
vis[t] = vis[u]+1;
q.push(t);
}
}
if(pos < n && !book[pos+1])
{
int t = u+(1<<(3*i));
if(vis[t] == -1)
{
vis[t] = vis[u]+1;
q.push(t);
}
}
}
}
}

void init()
{
memset(vis, -1, sizeof(vis));
for(int i = 1; i <= 7; i++)
bfs(i);
}

int a[10], Hash[10];
int main(void)
{
init();
int _;
cin >> _;
while(_--)
{
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]), Hash[i] = a[i];
sort(Hash+1, Hash+1+n);
int d = unique(Hash+1, Hash+1+n)-Hash-1;
for(int i = 1; i <= n; i++)
a[i] = lower_bound(Hash+1, Hash+1+d, a[i])-Hash-1;
int sta = 0;
for(int i = 1; i <= n; i++)
sta += i*(1<<(3*a[i]));
printf("%d\n", vis[sta]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  hihocder 状压 搜索