CSP考试复习:第三单元 3.3 8数码问题

   3.3 8  数码问题

  【问  题 描  述 】用最 少的 步 数 实现( 空 格 用 0  表 示):   

  (1)  BFS  

typedef int state[9];
const int N=1000000;
state st[N],goal;
int dist[N],parent[N];
const int dx[]={-1,1,0,0}, dy[]={0,0,-1,1};
void print(int p)
{
if (parent[p]!=-1) print(parent[p]);
// 输出st[p]
state &s=st[p];
cout<<s[0]<<" "<<s[1]<<" "<<s[2]<<endl;
cout<<s[3]<<" "<<s[4]<<" "<<s[5]<<endl;
cout<<s[6]<<" "<<s[7]<<" "<<s[8]<<endl;
cout<<endl;
}
int BFS() // 返回目标状态在st[]中的下标
{
init_lookup_table(); // 初始化查找表(判重用)
int front=1, rear=2;
parent[front]=-1;
while (front<rear)
{
state &s=st[front];
if (memcmp(goal, s, sizeof(s))==0) return front;
int z;
for (z=0; z<9; z++) if (s[z]==0) break; // 找“零”
int x=z/3, y=z%3; // “0”的行列编号
for (int d=0; d<4; d++)
{
int newx=x+dx[d];
int newy=y+dy[d];
int newz=newx*3+newy;
if (newx>=0 && newx<3 && newy>=0 && newy<3)
{
state &t=st[rear];
memcpy(&t, &s, sizeof(s)); // 扩展结点
t[newz]=s[z];
t[z]=s[newz];
dist[rear]=dist[front]+1;
parent[rear]=front;
if (try_to_insert(rear)) rear++;
}
}
front++;
}
return 0;
}

(2) 顺序化 *
下面的   代   码 把  0~ 8  的 全 排列 和   0~ 362879( 9 ! -1 ) 的 整数 一 一对 应 起 来。

bool visited[362880];
int fact[9];
void init_lookup_table()
{
fact[0]=1;
for (int i=1;i<9;i++) fact[i]=fact[i-1]*i;
}
bool try_to_insert(int s)
{
int code=0; // 把st[s]映射到整数code
state &p = st[s];
for (int i=0; i<9; i++)
{
int cnt=0;
for (int j=i+1; j<9; j++)
if (p[j]<p[i])
code+=fact[8-i]*cnt;
}
if (visited[code])
return false;
else
return visited[code]=true;
}

 (3)  使用   哈希表判重
上面 的 编   码 法  时 间效率 很高 , 但是 毕 竟 不 是通 用的方法 。如果 结点数 非 常大,编码 也是无法 承受的 。   

const int MAXSIZE = 1000003;
int head[MAXSIZE], next[MAXSIZE];
void init_lookup_table() {memset(head,0,sizeof(head));}
int h(state &s)
{
// 散列函数:把每个格子里数连接成一个九位数,并将它除以MAXSIZE的余数作为哈希函数值。
int v=0;
for (int i=0; i<9; i++) v=v*10+s[i];
return v%MAXSIZE;
}
bool try_to_insert(int s)
{
int h=hash(st[s]);
int u=head[h];
while (u){
if (memcmp(st[u],st[s],sizeof(st[s]))==0) return false;
u=next[u];
}
next[s]=head[h];
head[h]=s;
return true;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值