HDU 2234 无题I (BFS,映射)

题目: LINK

如果对于每个数据,直接搜索5步内能否到达终态,会TLE。
其实,可以发现终态是固定的,就是2*4!种。所以可以从终态开始搜索。 
1111
2222
3333
4444

1234
1234
1234
1234
以这两个为初始状态搜索,相当于预处理。之后对于每个输入的数据可以进行映射,其实就是4!种的排列。对于每一种映射,取步数最少的就可以了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define INF 1000000000
#define N 100111
typedef __int64 LL;
struct node
{
    LL num;
    int step;
};
node S;
struct no
{
    int mat[9][9];
};//
int vis[10], match[10], ans;
map<LL, int> mm;
no t, ret, xx;
LL change(LL x, int id)
{
    for(int i = 4; i>=1; i--) {
        for(int j = 4; j >= 1; j--){
            t.mat[i][j] = x % 4; x /= 4;
        }
    }
    ret = t;
    if(id<=4) {
        for(int i = 1; i<=3; i++) ret.mat[id][i] = t.mat[id][i+1];
        ret.mat[id][4] = t.mat[id][1];
    }
    else if(id <= 8) {
        id = id - 4;
        for(int i = 4; i>=2; i--) ret.mat[id][i] = t.mat[id][i-1];
        ret.mat[id][1] = t.mat[id][4];
    }
    else if(id <=12) {
        id = id - 8;
        for(int i = 1; i <= 3; i++) ret.mat[i][id] = t.mat[i+1][id];
        ret.mat[4][id] = t.mat[1][id];
    }
    else if(id <=16) {
        id = id - 12;
        for(int i = 4; i>=2; i--) ret.mat[i][id] = t.mat[i-1][id];
        ret.mat[1][id] = t.mat[4][id];
    }
    LL rr = 0;
    for(int i = 1; i <= 4; i++) {
        for(int j = 1; j <= 4; j++) rr *= 4, rr += ret.mat[i][j];
    }
    return rr;
}
void bfs()
{
    S.step = 1;
    queue<node > Q;
    Q.push(S);
    mm[S.num] = 1;
    node now, next;
    while(!Q.empty()) {
        now = Q.front(); Q.pop();
        if(now.step > 6) continue;
        for(int i = 1; i <= 16; i++) {//进行 16种变换
            next.num = change(now.num, i);
            next.step = now.step + 1;
            if(next.step > 6) continue;
            if(mm[next.num] == 0)  mm[next.num] = INF;
            if(mm[next.num] > next.step) {
                mm[next.num] = next.step;
                Q.push(next);
            }
        }
    }
}
void dfs(int id)
{
    if(id > 3) {
        LL tmp = 0;
        for(int i = 1; i <= 4; i++) {
            for(int j = 1; j <= 4; j++) {
                LL tt = match[xx.mat[i][j]];
                tmp *= 4; tmp += tt;
            }
        }
        int flag = mm[tmp] ;
        if(flag == 0) return ;
        ans = min(ans, flag);
        return ;
    }
    for(int i = 0 ; i <= 3; i++) {
        if(vis[i]) continue;
        match[id] = i; vis[i] = 1;
        dfs(id + 1);
        vis[i] = 0;
    }
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
#endif // ONLINE_JUDGE
    S.num = 0;
    for(int i = 1; i <= 4; i++) {
        for(int j = 1; j <= 4; j++) {
            S.num *= 4; S.num += i-1;
        }
    }
    bfs();
    S.num = 0;
    for(int i = 1; i <= 4; i++) {
        for(int j = 1; j <= 4; j++) {
            S.num *= 4; S.num += j-1;
        }
    }
    bfs();
    int t;
    scanf("%d",&t);
    while( t -- ) {
        for(int i = 1; i<=4; i++) {
            for(int j = 1; j <= 4 ; j++) {
                scanf("%I64d", &xx.mat[i][j]);
                xx.mat[i][j] -- ;
            }
        }
        ans = INF;
        memset(vis, 0, sizeof(vis));
        dfs(0);
        if(ans >= INF) puts("-1");
        else printf("%d\n", ans-1);
    }
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值