HDU 3220 Alice’s Cube (09年上海区域赛水题(位压缩、逆向搜索、打表))

       这道题是09年上海区域赛的A题,虽然很水,但是不能直接爆搜,直接爆搜要T。于是我们看到题目的要求是说当操作的步数大于3的时候就输出more,那么我们可以从终态枚举进行了三次操作所能达到的所有状态,这个是用广搜应该还是很好写的。我们直接使用vis数组就完全可以胜任这个记录了,没有必要用任何的结构体。

       我们在枚举操作的时候,因为我们仅仅只有32条边,我们直接手工输入这32条边,然后在广搜的过程中直接枚举边进行操作就行了,但是注意的一点是,题目中的要求是说这条边的两个端点的灯的状态必须是不一样的,才能进行操作,我在这个地方差点wa到死,好伤心啊!最后使用vis数组判断,进行相应的输出就可以了。

       下面贴上我的代码(代码应该还是比较简洁清晰的):

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
using namespace std;
int a[32]={1,3,2,1,10,2, 4, 1,3, 9, 9, 11,  6,14,6, 8, 5,13,5, 7, 13,15,5,7,  2,4,12,10,3,1,11,9};
int b[32]={2,4,4,3,12,10,12,9,11,11,10,12,  8,16,14,16,7,15,13,15,14,16,6,8,  6,8,16,14,7,5,15,13};
int vis[1000000];
int getState(int *st)
{
    int ans=0;
    for(int i=0;i<16;i++)
    {
        if(st[i])
        {
            ans|=(1<<i);
        }
    }
    return ans;
}

void bfs(int s)
{
    vis[s]=0;
    queue<int> q;
    q.push(s);
    while(!q.empty())
    {
        int fr=q.front();
        q.pop();
        if(vis[fr]>=3)
            continue;
        for(int i=0;i<32;i++)
        {
            int temp=fr;
            int j1=fr&(1<<(a[i]-1));
            int j2=fr&(1<<(b[i]-1));
            if(j1==j2)
                continue;
            temp^=(1<<(a[i]-1));
            temp^=(1<<(b[i]-1));
            if(vis[temp]==-1)
            {
                vis[temp]=vis[fr]+1;
                if(vis[temp]<3)
                    q.push(temp);
            }
        }
    }
}
int main()
{
    int st[16]={0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1};
    int s=getState(st);
    memset(vis,-1,sizeof(vis));
    bfs(s);
    int T;
    scanf("%d",&T);
    for(int cas=1;cas<=T;cas++)
    {
        for(int i=0;i<16;i++)
            scanf("%d",&st[i]);
        s=getState(st);
        printf("Case #%d: ",cas);
        if(vis[s]==-1||vis[s]>3)
            printf("more\n");
        else
            printf("%d\n",vis[s]);
    }
    return 0;
}


你可能感兴趣的:(HDU 3220 Alice’s Cube (09年上海区域赛水题(位压缩、逆向搜索、打表)))