ACM之八数码问题----BFS搜索----数独游戏的模拟(下)

题目描述;数独游戏的内核代码
八数码问题;
编号为1到8的8个正方形滑块被摆成3行3列;(有一个格子留空);
每次可以把与空格相邻的滑块(有公共边才算相邻)移到空格中;
而它原来的位置就成为了新的空格;给定初始局面和目标局面(用0表示空格);
你的任务死计算出最少的移动步数;和移动过程;如果无法到达目标局面,则输出-1;

------------------------------------------------------------------------------

接前面两个博客,在这个博客里,我们尝试改变我们使用的判重的数据结构;在第一个博客里我们用的是

数组,也就是顺序结构,速度非常的慢,在第二个博客里我们使用是c++里的set类库,其结构是一种特殊的红黑树

同时使用,整数来存储状态,加快了速度,体现了选择正确的数据结构的重要性,在本博客里,展示的是使用哈希技术实现的随机访问;

随机访问,也就是下标访问法;速度很快;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#include <iostream>
#include <fstream>
using namespace std;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>//因为这里要用到memcmp和memcpy函数;
//这两个函数比我们写的循环效率要高;
#define MAX 1000000
//为什么选择这么大呢?排列数9!;
typedef struct Node
{
    int state[9];//存放本状态各个位置的数码值;
    int fa;//记录父节点的下标;
    int deepth;
    int last_x;
    int last_y;
 
}Node;
Node q[MAX];//构成状态数组;
int head[MAX];
int hash_next[MAX];
const int dx[4]={-1,1,0,0};//左右上下;
const int dy[4]={0,0,-1,1};
int bfs();//广度优先找到目标状态;
void print_path(int founded);//根据fa成员,通过递归技术实现状态依次输出;
Node destination;//存储目标状态;
int i,j,k;
int main()
{
    /*首先输入起始状态和目标状态;*/
    memset(q,0,sizeof q);
    for(i=0;i<9;i++)
    {
        scanf("%d",&(q[0].state[i]));
    }
    for(i=0;i<9;i++)
    {
        scanf("%d",&destination.state[i]);
    }
        memset(head,0,sizeof head);
    memset(hash_next,0,sizeof hash_next);
     
    /*然后进行搜索并输出;*/
    int founded=bfs();
    if(founded)
    {
        printf("%d\n",q[founded].deepth);
        print_path(founded);
    }
    else
        printf("-1\n");
    system("pause");
    return 0;
}
int bfs()
{
    int front=1,rear=2;//用来模拟队列的先进先出,达到广度优先的目的;
    int v=0;
    q[1].deepth=0;
    q[1].fa=1;
    for(k=0;k<9;k++)
    {
        v=10*v+q[front].state[k];
    }
    v=v%MAX;
    head[v]=1;
     
    while (front<rear)
    {
        Node &first=q[front];
        if (memcmp(first.state,destination.state,sizeof destination.state)==0)
        {//找到了目标状态;
            return front;
        }
        for(i=0;i<9;i++)
            if (!first.state[i])
            {//找到空格处;
                break;
            }
 
        for(j=0;j<4;j++)
        {//向四个方向进行转换;
            Node &new_Node=q[rear];
            memcpy(new_Node.state,first.state,sizeof first.state);
            int new_x=i%3+1+dx[j];
            int new_y=i/3+1+dy[j];
             
            if (new_x>0&&new_y>0&&new_x<4&&new_y<4)
            {
                //位置合法;
                new_Node.state[i]=new_Node.state[i+dx[j]+3*dy[j]];//空格位置;
                new_Node.state[i+dx[j]+3*dy[j]]=0;//新的状态形成了;
                 
                v=0;
                for(k=0;k<9;k++)//这里不用i,j因为i,j是全局变量且本函数是在循环里面的;
                {
                    v=10*v+new_Node.state[k];
                }
                v=v%MAX;
                int u=head[v];
                int found=0;
                while(u)
                {
                    if(memcmp(q[u].state,new_Node.state,sizeof new_Node.state)==0)
                    {
                        found=1;
                        break;
                    }
                    u=hash_next[u];
                }
 
                if(!found)//没有被访问;
                {
 
                    new_Node.fa=front;
                    new_Node.deepth=first.deepth+1;
                    new_Node.last_x=dx[j];
                    new_Node.last_y=dy[j];
                    hash_next[rear]=head[v];
                    head[v]=rear;
                     
                    rear++;
                }//if
                 
            }//if
        }//for
        front++;
        //printf("%d %d\n",front,q[front].deepth);
    }//while
    return 0;
}
void print_path(int founded)
{
    if(q[founded].fa!=founded)
    {
        print_path(q[founded].fa);
    }
    for(i=0;i<3;i++)
    {
        for(j=0;j<3;j++)
        {
            printf("%d ",q[founded].state[3*i+j]);
        }
        printf("\n");
    }
    printf("\n");
}

这里使用了哈希技术,把状态进行操作,使其作为下标;这样就能不受数组大小的限制,马上访问到对应的状态;

哈希表的执行效率高,适用的范围很广,可以快速的查找;

posted @   在河之博  阅读(804)  评论(2编辑  收藏  举报
点击右上角即可分享
微信分享提示