HDU 2234 无题I

HDU_2234

    这个题目可以先从终态出发,把5步以内的所有状态预处理出来,同时为了进一步减少状态,利用最小表示法的思想,将终态看成只有两种:

1111

2222

3333

4444

1234

1234

1234

1234

,这样我的程序最终跑出来就只有157370个状态了。

    在查询的时候,由于前面我们用最小表示法将状态简化了,那么现在就要将1、2、3、4全排列一下生成24种状态,每种状态都查找一下,然后取这24种状态下的最小值。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define HASH 1000007
#define MAXD 1000010
#define INF 0x3f3f3f3f
typedef unsigned int _int;
struct HashMap
{
    int head[HASH], size, next[MAXD];
    _int st[MAXD];
    void init()
    {
        memset(head, -1, sizeof(head));
        size = 0;
    }
    int find(_int _st)
    {
        int i, h = _st % HASH;
        for(i = head[h]; i != -1; i = next[i])
            if(st[i] == _st) break;
        return i;    
    }
    void push(_int _st)
    {
        int h = _st % HASH;    
        st[size] = _st;
        next[size] = head[h], head[h] = size ++;
    }
}hm;
int trans[][4] =
{
    {0, 1, 2, 3}, {0, 1, 3, 2}, {0, 2, 1, 3}, {0, 2, 3, 1}, {0, 3, 1, 2}, {0, 3, 2, 1},
    {1, 0, 2, 3}, {1, 2, 0, 3}, {1, 2, 3, 0}, {1, 0, 3, 2}, {1, 3, 0, 2}, {1, 3, 2, 0},
    {2, 0, 1, 3}, {2, 0, 3, 1}, {2, 1, 0, 3}, {2, 1, 3, 0}, {2, 3, 0, 1}, {2, 3, 1, 0},
    {3, 0, 1, 2}, {3, 0, 2, 1}, {3, 1, 0, 2}, {3, 1, 2, 0}, {3, 2, 0, 1}, {3, 2, 1, 0},
};
_int q[MAXD];
int  dis[MAXD], code[4][4];
_int encode(int code[][4])
{
    int i, j;
    _int ans = 0;
    for(i = 0; i < 4; i ++)
        for(j = 0; j < 4; j ++) ans = ans << 2 | code[i][j];
    return ans;
}
void decode(_int st)
{
    int i, j;
    for(i = 3; i >= 0; i --)
        for(j = 3; j >= 0; j --) code[i][j] = st & 3, st >>= 2;
}
void shr(int r, int k)
{
    int i;
    if(k == 0) for(i = 0; i < 3; i ++) std::swap(code[r][i], code[r][i + 1]);
    else for(i = 3; i >= 1; i --) std::swap(code[r][i], code[r][i - 1]);
}
void shc(int c, int k)
{
    int i;
    if(k == 0) for(i = 0; i < 3; i ++) std::swap(code[i][c], code[i + 1][c]);
    else for(i = 3; i >= 1; i --) std::swap(code[i][c], code[i - 1][c]);    
}
void prepare()
{
    int i, j, k, rear = 0;
    _int x, y;
    hm.init();
    for(i = 0; i < 4; i ++)
        for(j = 0; j < 4; j ++) code[i][j] = i;
    x = encode(code);
    hm.push(x), q[rear ++] = x;
    for(i = 0; i < 4; i ++)
        for(j = 0; j < 4; j ++) code[i][j] = j;
    x = encode(code);
    hm.push(x), dis[rear] = 0, q[rear ++] = x;
    for(i = 0; i < rear; i ++)
    {
        if(dis[i] >= 5) continue;
        x = q[i];
        decode(x);
        for(j = 0; j < 4; j ++)
            for(k = 0; k < 2; k ++)
            {
                shr(j, k);
                y = encode(code);
                if(hm.find(y) == -1)
                    hm.push(y), dis[rear] = dis[i] + 1, q[rear ++] = y;
                shr(j, k ^ 1);
                shc(j, k);
                y = encode(code);
                if(hm.find(y) == -1)
                    hm.push(y), dis[rear] = dis[i] + 1, q[rear ++] = y;
                shc(j, k ^ 1);    
            }    
    }
    //printf(">> %d\n", rear);
}
void solve()
{
    int i, j, k, g[4][4], ans = INF;
    for(i = 0; i < 4; i ++)
        for(j = 0; j < 4; j ++) scanf("%d", &g[i][j]), -- g[i][j];
    for(k = 0; k < 24; k ++)
    {
        for(i = 0; i < 4; i ++)
            for(j = 0; j < 4; j ++) code[i][j] = trans[k][g[i][j]];
        i = hm.find(encode(code));
        if(i != -1) ans = std::min(ans, dis[i]);
    }
    if(ans == INF) printf("-1\n");
    else printf("%d\n", ans);
}
int main()
{
    prepare();
    int t;
    scanf("%d", &t);
    while(t --)
        solve();
    return 0;    
}
原文地址:https://www.cnblogs.com/staginner/p/2660223.html