hiho1233--Boxes(BFS)

题目大意:有n个盘子,n个柱子,每个柱子上都有一个盘子,任意两个盘子大小均不相同,一个盘子可以移动到相邻的柱子上,且必须比该柱子最上方的盘子要小,问最少移动多少次后,盘子从小到大依次摆在每个柱子上。


分析:首先,最少步的问题,说明,要用BFS。

          其次,多个起点,固定终点,说明,可以预处理,反向BFS。

          然后,就是考虑如何表示状态了。由于一个柱子上可以有多个盘子,所以,并不能有盘子的编号来表示状态。于是,我们可以考虑用每个盘子的位置表示当前的状态。又n最大为7,所以状态数最多8^7种。


代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;

#define maxn 11111111
int dp[maxn];   //从初始状态到每种状态的最小步数
int pos[10];    //pos[i] = j,表示第j个盘子在第i个位置
int dig[10];    //dig[i] = j,表示第i个盘子移动一次,状态变化j

void bfs(int x) {
    int state, t, temp, head;
    dig[x] = 1;
    for(int i = x-1; i >= 1; i--)
        dig[i] = dig[i+1]*8;
    state = 0;
    for(int i = 1; i <= x; i++)
        state = state*8+i;
    dp[state] = 0;
    queue<int> q;
    q.push(state);
    while(!q.empty()) {
        t = head = q.front();
        q.pop();
        memset(pos, 0, sizeof(pos));
        for(int i = x; i >= 1; i--, t /= 8)     //确定每个位置最上方的盘子
            pos[t%8] = i;
        for(int i = 1; i <= x; i++) {
            if(pos[i] == 0) continue;
            if(i > 1 && (pos[i] < pos[i-1] || !pos[i-1])) {     //第i个盘子向前移
                temp = head-dig[pos[i]];
                if(dp[temp] == -1) {
                    dp[temp] = dp[head]+1;
                    q.push(temp);
                }
            }
            if(i < x && (pos[i] < pos[i+1] || !pos[i+1])) {    //第i个盘子向后移
                temp = head+dig[pos[i]];
                if(dp[temp] == -1) {
                    dp[temp] = dp[head]+1;
                    q.push(temp);
                }
            }
        }
    }
}

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

int main() {
    init();
    int n, T, loc[11111], a[10];    //loc[i]表示盘子i所在的位置
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            loc[a[i]] = i;
        }
        sort(a+1, a+n+1);
        int st = 0;
        for(int i = 1; i <= n; i++)
            st = st*8 +loc[a[i]];
        printf("%d\n", dp[st]);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值