hihoCoder 1233 Boxes(状态压缩)

题目链接:

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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值