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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章