题意:初始状态为左边空一行,数字在右边28个格子。末态要按一副卡片在一行顺序牌,即第一行为11-17,第二行21-27,。。。。,可以通过四个空格来转移卡片,问从初始状态到末态最少要多少步。
分析:
1、每次操作只能把一个数字放到某个空格,不能交换两个数字的位置。
2、用的是再哈希法hash =(v+10)%M来处理冲突。
3、空格的左边为空或者数字的末尾为7则不能填充。
4、填充空格要找比他左边大1的数来填充。
#include<iostream>
#include<queue>
using namespace std;
#define MOD 1000007
__int64 Hash[1000007]; //hash表,用于hash判重
struct Node
{
int map[4][8]; //图
int step; //步数
bool operator==(const Node& p)const //判断相等
{
int i,j;
for(i=0;i<4;i++)
for(j=0;j<8;j++)
if(map[i][j]!=p.map[i][j])
return false;
return true;
}
__int64 HashValue() //hash值
{
__int64 v=0;
int i,j;
for(i=0;i<4;i++)
for(j=0;j<8;j++)
v+=(v<<1)+map[i][j];
return v;
}
};
Node s,e; //初始节点和结束节点
void Swap(int& a,int& b)
{
int tmp;
tmp=a;
a=b;
b=tmp;
}
void Read()
{
int i,j;
memset(Hash,-1,sizeof(Hash));
for(i=0;i<4;i++) //初始第0列为空
{
s.map[i][0]=0;
for(j=1;j<8;j++)
scanf("%d",&s.map[i][j]);
}
s.step=0;
}
void GetEnd() //获得终态
{
int i,j;
for(i=0;i<4;i++)
{
e.map[i][7]=0;
for(j=0;j<7;j++)
e.map[i][j]=(i+1)*10+(j+1);
}
}
bool HashJudge(__int64 value) //hash判重
{
int v;
v=value%MOD;
while(Hash[v]!=-1 && Hash[v]!=value) //冲突处理,在hash法
{
v+=10;
v%=MOD;
}
if(Hash[v]==-1)
{
Hash[v]=value;
return true;
}
return false;
}
bool bfs(int& ans)
{
queue<Node> q;
Node p,p2;
int i,j,x,y,value,k,l;
bool fg;
__int64 ha;
q.push(s); //初始节点入队
HashJudge(s.HashValue());
while(!q.empty())
{
p=q.front();
q.pop();
for(i=0;i<4;i++)
for(j=0;j<8;j++)
{
if(!p.map[i][j]) //格子为空
{
p2=p;
p2.step++;
value=p.map[i][j-1]+1; //找比map[i][j-1]大1的数
if(value==1||value%10==8) //0或者value为7的不能移动
continue;
fg=true;
for(k=0;k<4&&fg;k++)
for(l=1;l<8&&fg;l++)
if(p.map[k][l]==value)
{
x=k;
y=l;
fg=false;
}
if(!fg)
{
Swap(p2.map[i][j],p2.map[x][y]);
ha=p2.HashValue();
if(HashJudge(ha)) //hash判重
{
if(p2==e)
{
ans=p2.step;
return true;
}
q.push(p2);
}
}
}
}
}
return false;
}
void Process()
{
int k,i,j,ans;
k=0;
for(i=0;i<4;i++) //初始时将11,21,31,41移动到第0列
for(j=1;j<8;j++)
if(s.map[i][j]==(k+1)*10+1)
{
Swap(s.map[i][j],s.map[k][0]);
k++,i=0,j=0;
}
if(s==e)
{
cout<<0<<endl; //前四步不记录
return ;
}
if(bfs(ans))
cout<<ans<<endl;
else
cout<<-1<<endl;
}
int main()
{
int T;
scanf("%d",&T);
GetEnd();
while(T--)
{
Read();
Process();
}
return 0;
}
原文地址:http://blog.csdn.net/a809146548/article/details/46390375