八数码问题(hash+bfs)

小白P131
编号为1~8的8个正方形滑块被摆成3行3列(有一个格子留空)。每次可以把与空格相邻的滑块(有公共边才算相邻)移到空格中,而它原来的位置就成为了新的空格。给定初始局面和目标局面(用0表示空格),你的任务是计算出最少的移动步数。如果无解,输出-1。

这里写图片描述

#include<stdio.h>
#include<string.h>

const int N=1000000,HN=1000003;
int nx[4][2]={-1,0,1,0,0,-1,0,1};//上下左右 

int start[N][9],goal[9];//起始数组,目标数组 
int first[HN],next[N];//链表 
int step[N];

int hash(int *start)//通过hash函数将每种状态转换成相同长度的整数 
{
    int ha=0;
    for(int i=0;i<9;i++)
        ha=ha*10+start[i];//这是一个hash映射函数,通过他可以实现转换 
    return ha%HN;
}

bool try_insert(int tail)//相当于判断if(book[tx][ty]==0) 
{
    int ha=hash(start[tail]);
    int u=first[ha];
    while(u)
    {
        if(!memcmp(start[u],start[tail],sizeof(start[0]))) return 0;//如果已经走过则返回0 
        u=next[u];//顺着链表继续找 
    }
    next[tail]=first[ha];
    first[ha]=tail;//将这个点插入到链表中 
    return 1;//没有走过,扩展成功,返回1 
}

int bfs()
{
    memset(first,0,sizeof(first));
    int head=1,tail=2;
    while(head<tail)
    {
        if(memcmp(goal,start[head],sizeof(start[0]))==0) return head;//找到目标状态 

        int z;//注意将数据带出 
        for(z=0;z<9;z++) 
            if(start[head][z]==0) break;//找到"0" 
        int x=z/3,y=z%3;//转化为坐标形式,x表示行y表示列 

        for(int i=0;i<4;i++)
        {
            int tx=x+nx[i][0];
            int ty=y+nx[i][1];
            int tz=3*tx+ty;//行x列y移动后再转化为下标形式 

            if(tx>=0&&tx<3&&ty>=0&&ty<3)//总共3行3列 
            {
                memcpy(&start[tail],&start[head],sizeof(start[0]));//将head中的点给tail 
                start[tail][tz]=start[head][z];
                start[tail][z]=start[head][tz];//将0所在的格与旁边的格中的数值交换 
                step[tail]=step[head]+1;//步数+1 
                if(try_insert(tail)) tail++;//相当于book,如果这步扩展成功则tail++ 
            }
        }
        head++;
    }
    return 0;
}

int main()
{

    for(int i=0;i<9;i++)
        scanf("%d",&start[1][i]);
    for(int i=0;i<9;i++)
        scanf("%d",&goal[i]);

    int s=bfs();
    if(s>0) printf("%d\n",step[s]);
    else printf("-1\n");

    return 0;
}
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define M 500000
#define Mod 1000003
using namespace std;

int s[9],goal[9],head[Mod],Next[Mod],end,director[M],tt,f;
int nx[4][2]={0,-1,1,0,0,1,-1,0};

struct node
{
    int str[9];
    int step,first,dir;
}Q[M];              

int Hash(int ss[])
{
    int sum=0;
    for(int i=0;i<9;i++)
        sum=sum*10+ss[i];
    return sum%Mod;
}

int Try_to_insert(int ss)
{
    int h=Hash(Q[ss].str);
    int u=head[h];
    while(u)
    {
        if(memcmp(Q[ss].str,Q[u].str,sizeof(goal))==0)
            return 0;
        u = Next[u];
    }
    Next[ss]=head[h];
    head[h]=ss;
    return 1;
}

void find(int x)
{
    if(Q[x].dir==-1)
        return ;
    else
    {
        find(Q[x].first);
        director[tt++]=Q[x].dir;
    }
}

void bfs()
{
    memcpy(Q[1].str,s,sizeof(s));

    int head=1,tail=2;
    Q[head].step=0;
    Q[head].first=0;
    Q[head].dir=-1;

    Try_to_insert(1);

    while(head<tail)
    {

        int z;
        for(z=0;z<9;z++)
            if(!Q[head].str[z]) break;
        int y=z/3,x=z%3;

        for(int i=0;i<4;i++)
        {
            int tx=x+nx[i][0];
            int ty=y+nx[i][1];
            if(tx>=0&&tx<3&&ty>=0&&ty<3)
            {
                int tz=3*ty+tx;
                memcpy(Q[tail].str,Q[head].str,sizeof(goal));

                swap(Q[tail].str[z],Q[tail].str[tz]);

                if(Try_to_insert(tail))
                {
                    Q[tail].step=Q[head].step+1;
                    Q[tail].first = head;
                    Q[tail].dir = i;        
                    if(memcmp(Q[tail].str,goal,sizeof(goal))==0)
                    {
                        f=1;
                        end=tail;
                        return ;
                    }
                    tail++;
                }

            }
        }
        head++;
    }
}

int main()
{
    int i,j,k,t,n;
    char ss[1000];
    while(gets(ss)!=NULL)
    {
        int l=strlen(ss);
        k=0;
        for(i=0;i<l;i++)
        {
            if(ss[i]>='0'&&ss[i]<='9')
                s[k++]=ss[i]-'0';
            if(ss[i]=='x')
                s[k++]=0;
        }
        for(i=1;i<=9;i++)
        {
            if(i==9) goal[i-1]=0;
            else goal[i-1]=i;
        }

        if(memcmp(s,goal,sizeof(s))==0)
        {
            printf("\n");
            continue;
        }

        memset(head,0,sizeof(head));
        end=1;
        f=0;
        bfs();
        tt=0;
        if(f)
        {
            find(end);
            for(i=0;i<tt;i++)
            {
                if(director[i]==0) printf("u");
                else if(director[i]==1) printf("r");
                else if(director[i]==2) printf("d");
                else if(director[i]==3) printf("l");
            }
            printf("\n");
        }
        else 
            printf("unsolvable\n");
    }
    return 0;       
} 
以下是使用A*搜索算法解决八数码问题的C语言代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXN 1000000 int dx[4] = {1, 0, -1, 0}; int dy[4] = {0, 1, 0, -1}; char dir[4] = {'d', 'r', 'u', 'l'}; int vis[MAXN], pre[MAXN], op[MAXN]; int fact[9], digits[9]; struct node { int puzzle[3][3]; int step, f; int hashvalue; }start, goal, node; void init_lookup_table() { fact[0] = 1; for (int i = 1; i < 9; i++) { fact[i] = fact[i-1] * i; } } int get_hashvalue(int puzzle[][3]) { int code = 0; for (int i = 0; i < 9; i++) { int cnt = 0; for (int j = i+1; j < 9; j++) { if (puzzle[j/3][j%3] < puzzle[i/3][i%3]) { cnt++; } } code += fact[8-i] * cnt; } return code; } int bfs() { init_lookup_table(); memset(vis, 0, sizeof(vis)); int front = 0, rear = 1; memcpy(node.puzzle, start.puzzle, sizeof(node.puzzle)); node.step = node.f = 0; node.hashvalue = get_hashvalue(node.puzzle); vis[node.hashvalue] = 1; while (front < rear) { memcpy(node.puzzle, op[front] ? goal.puzzle : start.puzzle, sizeof(node.puzzle)); node.step = pre[front] + 1; for (int i = 0; i < 9; i++) { if (!node.puzzle[i/3][i%3]) { int x = i/3, y = i%3; for (int j = 0; j < 4; j++) { int newx = x + dx[j]; int newy = y + dy[j]; if (newx >= 0 && newx < 3 && newy >= 0 && newy < 3) { memcpy(&node.puzzle[x][y], &node.puzzle[newx][newy], sizeof(int)); memcpy(&node.puzzle[newx][newy], &(digits[0]), sizeof(int)); node.hashvalue = get_hashvalue(node.puzzle); if (!vis[node.hashvalue]) { memcpy(op+rear, op+front, sizeof(op[front])); op[rear-1] = j; memcpy(pre+rear, pre+front, sizeof(pre[front])); pre[rear++] = node.step; memcpy(vis+node.hashvalue, &rear, sizeof(int)); node.f = node.step + get_hashvalue(node.puzzle); if (node.hashvalue == goal.hashvalue) { return rear-1; } } memcpy(&node.puzzle[newx][newy], &node.puzzle[x][y], sizeof(int)); memcpy(&node.puzzle[x][y], &(digits[0]), sizeof(int)); } } break; } } front++; } return -1; } int main() { for (int i = 0; i < 9; i++) { scanf("%d", digits+i); if (!digits[i]) { digits[i] = 9; } } for (int i = 0; i < 9; i++) { start.puzzle[i/3][i%3] = digits[i]; } for (int i = 0; i < 9; i++) { scanf("%d", digits+i); if (!digits[i]) { digits[i] = 9; } } for (int i = 0; i < 9; i++) { goal.puzzle[i/3][i%3] = digits[i]; } start.hashvalue = get_hashvalue(start.puzzle); goal.hashvalue = get_hashvalue(goal.puzzle); int rear = bfs(); if (rear == -1) { printf("unsolvable\n"); } else { printf("%d\n", pre[rear]); for (int i = rear-1; i >= 0; i--) { printf("%c", dir[op[i]]); } printf("\n"); } return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值