POJ -- 2965 The Pilots Brothers' refrigerator

题目连接: POJ -- 2965ios

题目给出的是4X4的矩阵,规模不算大。因为问的是最少的操做步数,很容易想到bfs宽搜。一共16个格子,总共的状态数是2^16,不算大,因此这个策略的确是对的。编程

可是须要注意到每一个“状态”都是一个4x4的矩阵,咱们须要想办法去记录一个矩阵的状态。用整数是一个直观的方法,咱们每次对当前矩阵作过变形后,新的矩阵存储于另外一个二维数组中,而后再算出表明新矩阵状态的整数。我 们存储这个整数就好。数组

可是这么作是会超时的。缘由是这个宽搜的出度特别大,出度也是16(当前矩阵每改变一个元素都会生成一个新矩阵,一共16个元素)。加上咱们在矩阵和表明矩阵的整数之间作变换也须要消耗O(16)的时间,一共花掉了O(16^2)。一共2^16个状态,咱们对每一个状态作O(16^2)的操做,这个复杂度是大于10^7了,会超时。函数

解决的办法是利用位运算。咱们将当前的矩阵用一个整数表明(和以前作的同样),当对元素(i, j)做翻转的时候,直接在整数上作文章就能完成(这个是能够达到的,就是很麻烦),这样不用在矩阵和整数之间来回转,省下了O(16)的复杂度。优化

#include <cstdio>
#include <iostream>
#include <queue>
using namespace std;
typedef unsigned short ushort;
char g[10][10];
int vis[100000], path[100000], from[100000];
ushort q[100000];
int front, end;
ushort get_id(char g[10][10])
{
    ushort id = 0;
    for(int i = 0; i < 4; i++)
    {
        for(int j = 0; j < 4; j++)
        {
            id <<= 1;
            if(g[i][j] == '+') id |= 1;
        }
    }
    return id;
}

ushort black_mask_r[4] = { (((1 << 4) - 1) << (3*4)), (((1 << 4) - 1) << (2*4)), (((1 << 4) - 1) << (1*4)), ((1 << 4) - 1) };
ushort white_mask_r[4] = { ~(((1 << 4) - 1) << (3*4)), ~(((1 << 4) - 1) << (2*4)), ~(((1 << 4) - 1) << (1*4)), ~((1 << 4) - 1) };
ushort mark = (1 | (1 << 4) | (1 << 2*4) | (1 << 3*4));
ushort black_mask_c[4] = { (mark << 3), (mark << 2), (mark << 1), mark};
ushort white_mask_c[4] = { ~(mark << 3), ~(mark << 2), ~(mark << 1), ~mark};

ushort change_ij(ushort st, int i, int j)
{
    ushort r = (st & black_mask_r[i]);
    r = ~r;
    r &= black_mask_r[i];
    ushort restr = st & white_mask_r[i];
    r = restr | r;

    ushort k = ((1 << (3-j)) << (4*(3-i)));
    r ^= k;

    ushort c = r & black_mask_c[j];
    c = ~c;
    c &= black_mask_c[j];
    ushort restc = r & white_mask_c[j];
    c = restc | c;
    return c;
}

ushort id;
void print_path(ushort st, int l)
{
    if(from[st] < 0)
    {
        printf("%d\n", l);
        return ;
    }
    print_path(q[from[st]], l+1);
    printf("%d %d\n", path[st]/4+1, path[st]%4+1);
}

int main()
{
    // freopen("in.txt", "r", stdin);

    for(int i = 0; i < 4; i++)
    {
        scanf("%s", g[i]);
    }
    id = get_id(g);

    vis[id] = 1; q[end++] = id; from[id] = -1;
    ushort ans = -1;
    while(front != end)
    {
        int index = front;
        ushort x = q[front++];
        if(!x) { ans = x; break; }
        for(int i = 0; i < 4; i++)
        {
            for(int j = 0; j < 4; j++)
            {
                ushort st = change_ij(x, i, j);
                if(!vis[st])
                {
                    q[end++] = st;
                    vis[st] = 1;
                    path[st] = 4*i+j;
                    from[st] = index;
                }
            }
        }
    }

    if(!ans)
    {
        print_path(0, 0);
    }
    return 0;
}

位运算的代码确实有点恶心,我编程能力差,调试了特别久。spa

代码优化时间就是用change_ij函数去代替在矩阵数组和整数之间来回转换,那个函数内部用的都是位运算,速度比4*4的循环快多了。调试

相关文章
相关标签/搜索