[NOIP模拟] 玩积木

3 篇文章 0 订阅
2 篇文章 0 订阅

题目大意 :

    给出初始的积木样子 :
    0
    1  1
    2  2  2
    3  3  3  3
    4  4  4  4  4
    5  5  5  5  5  5
    现将打乱,每次可将 0 和左上,上,下,右下的交换,求最小步数, 超过20, 输出 233。

输入简述 :

    输入 T , 表示数据,每组为打乱积木图。

输出简述 :

    T 个答案。

sample intput :

1
1
2  0
2  1  2
3  3  3  3
4  4  4  4  4
5  5  5  5  5  5

sample output :

3




题解 :

    这道题一看很板啊, A*套上就过了, 但是考后和别人聊了一下才发现我的是假的 A *, 因为我的是DFS,正版的是 BFS,后来想想也是, 难怪我的跑的那么慢。
    预估函数 : 当前步数 + 期望最小步数 < 20 , 最小步数位当前不匹配数。

代码 :

DFS 的 A*

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <ctime>
#include <map>
#include <vector>
#define LL long long
using namespace std;

inline int read() {
    int i = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9') {
        if(ch == '-') f = -1; ch = getchar();
    }
    while(ch >= '0' && ch <= '9') {
        i = (i << 3) + (i << 1) + ch - '0'; ch = getchar();
    }
    return i * f;
}

const int mod = 981256453;
int sta[7][7] = {
    {0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0},
    {0, 1, 1, 0, 0, 0, 0},
    {0, 2, 2, 2, 0, 0, 0},
    {0, 3, 3, 3, 3, 0, 0},
    {0, 4, 4, 4, 4, 4, 0},
    {0, 5, 5, 5, 5, 5, 5},
};
int a[7][7], ans, x[4] = {-1, -1, 1, 1}, y[4] = {-1, 0, 0, 1};
int zx, zy, vis[7][7], f[7][7], pow1[30], hao[7][7], tail;
map<LL, int> b;
map<int, LL> c;

inline int judge() {
    int now = 0;
    memset(f, 0, sizeof(f));
    for(int i = 1; i <= 6; ++i)
        for(int j = 1; j <= i; ++j)
            if(a[i][j] != sta[i][j])
                ++now, f[i][j] = 1;
    return now;
}

inline void print() {
    for(int i = 1; i <= 6; ++i) {
        for(int j = 1; j <= i; ++j)
            printf("%d ", a[i][j]);
        printf("\n");
    }
}

inline LL solve() {
    LL now = 0;
    for(int i = 1; i <= 6; ++i)
        for(int j = 1; j <= i; ++j)
            now = (now + (LL)a[i][j] * pow1[hao[i][j]] % mod) % mod;
    return now;
}

inline void dfs(int now, int lx, int ly) {
    int num = judge();
    if(!num) { ans = min(ans, now); return; }
    if(num + now > 20) return ;
    LL g = solve(); 
    if(!b[g]) b[g] = now + 1, c[++tail] = g;
    else if(b[g] > now + 1) b[g] = now + 1;
    else return ;
    for(int i = 0; i < 4; ++i) {
        int nx = lx + x[i], ny = ly + y[i];
        if(vis[nx][ny]) {
            swap(a[nx][ny], a[lx][ly]);
            dfs(now + 1, nx, ny);
            swap(a[nx][ny], a[lx][ly]);
        }
    }
}

inline void init() {
    int cnt = -1;
    for(int i = 1; i <= 6; ++i)
        for(int j = 1; j <= i; ++j)
            vis[i][j] = 1, hao[i][j] = ++cnt;
    pow1[0] = 1;
    for(int i = 1; i <= 20; ++i) pow1[i] = pow1[i - 1] * 7 % mod;
}

int main() {
    int times = read();
    init();
    while(times--) {
        for(int i = 1; i <= tail; ++i) b[c[i]] = 0; tail = 0;
        for(int i = 1; i <= 6; ++i)
            for(int j = 1; j <= i; ++j) {
                a[i][j] = read();
                if(!a[i][j]) zx = i, zy = j;
            }
        ans = 0x3f3f3f3f;
        dfs(0, zx, zy);
        if(ans != 0x3f3f3f3f) printf("%d\n", ans);
        else printf("233\n");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值