POJ 2046 Gap【题解报告|BFS&hash判重】

题目链接

题目大意

4*8的方格有28个数字,按照给定的规则移动,现在要你从初始状态移动到终结状态,问你最少几步.

思路分析

依然是BFS,且每个状态需要的元素很多。所以用dist[][][][][]…[]这种形式空间不足,所以需要用hash判重且保存所有出现过的状态。

首先我们每个状态要用一个32位的char数组s保存32个方格中的每个数字,然后我们用e[4]数组保存32个方格中(有4个0)4个0的位置分别是多少,并且用p[48]保存XY(11<=XY<=47)这个数字在s数组中的位置.用dist表示我们最少走几步能到该状态s[32]

这个题目还要用到hash来判断我们新生成的状态s是否已经出现了.

本题大体框架和一般的BFS问题没区别,关键在于注意各种细节,别出错.

#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1000000+7;
struct node
{
    char s[32],e[4],p[48];
    int dist;                        //错误1,忘了写dist
}Q[maxn/2];
int head[maxn],next[maxn/2];//数组大小探测得出,head[i]==-1表示不存在
int hash(char *s)//获得哈希值
{
    unsigned int v=0;
    for(int i=0;i<=31;i++) v=v*7+s[i];
    return v%maxn;
}
void insert(int i)//我们先find(s)之后知道i不存在,才直接insert
{
    int h=hash(Q[i].s);
    next[i]=head[h];
    head[h]=i;
}
int cmp(char *s1,char *s2)//不同返回1,相同返回0
{
    for(int i=0;i<=31;i++)
        if(s1[i]!=s2[i]) return 1;
    return 0;
}
void cpy(char *s1,char *s2,int n)
{
    for(int i=0;i<n;i++) s1[i]=s2[i];
}
int find(char *s)
{
    int h=hash(s);
    int u=head[h];
    while(u>=0)
    {
        if(cmp(Q[u].s,s)==0) return u;
        u=next[u];
    }
    return -1;//未找到
}
void get(char &a)
{
    char ch=getchar();
    while(!(ch>='0'&&ch<='9')) ch=getchar();
    for(a=0; (ch>='0'&&ch<='9') ;ch=getchar()) a=a*10+ch-'0';
    if(a==11||a==21||a==31||a==41) a=0;
}
int BFS()
{
    int front=1,tail=2,suc_v,suc_p,e_pos,k;//suc_v后继的值,suv_p后继的位置,e_pos表0的位置
    while(tail>front)
    {
        for(int i=0;i<4;i++)//对于4个0的位置
        {
            cpy(Q[tail].s,Q[front].s,32);
            if((e_pos=Q[front].e[i])>0 && Q[front].s[e_pos-1]%10<7 && Q[front].s[e_pos-1]!=0 )
            {//上面3个判断对应于: 0的左边不是边界  0的坐左边值有后继  0的左边不是0
                Q[tail].s[e_pos]=suc_v=Q[front].s[e_pos-1]+1;
                Q[tail].s[ suc_p=Q[front].p[suc_v] ]=0;
                if( (k=find(Q[tail].s))<0)//该状态原先没有
                {
                    cpy(Q[tail].e, Q[front].e,4);
                    cpy(Q[tail].p, Q[front].p,48);
                    Q[tail].e[i]=suc_p;
                    Q[tail].p[suc_v]=e_pos;
                    Q[tail].dist=Q[front].dist+1;
                    insert(tail);
                    tail++;
                }
                else if(k==0) return Q[front].dist+1;//找到了终态
            }
        }
        front++;
    }
    return -1;
}
int main()
{
    for(int i=0;i<4;i++)
    for(int j=0;j<7;j++)
        Q[0].s[i*8+j]=(i+1)*10+j+1;            //错误2 写成了(i/8+1)*10+j+1 了
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(head,-1,sizeof(head));
        insert(0);
        for(int i=0;i<4;i++)
            for(int j=1;j<=7;j++)
                get(Q[1].s[i*8+j]) , Q[1].p[Q[1].s[i*8+j]]=i*8+j;
        for(int i=0;i<4;i++)//处理第一列
            Q[1].s[i*8]=(i+1)*10+1 , Q[1].p[Q[1].s[i*8]] = i*8;
        if(find(Q[1].s)==0) printf("0\n");
        else
        {
            int k=0;
            for(int i=0;i<4;i++)
                for(int j=0;j<8;j++)if(Q[1].s[i*8+j]==0)
                    Q[1].e[k++]=i*8+j;
            Q[1].dist=0;
            insert(1);
            printf("%d\n",BFS());
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章