題目大意
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;
}