九宫重排

27 篇文章 0 订阅
2 篇文章 0 订阅

问题描述
  如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。

  我们把第一个图的局面记为:12345678.
  把第二个图的局面记为:123.46758
  显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
  本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。
输入格式
  输入第一行包含九宫的初态,第二行包含九宫的终态。
输出格式
  输出最少的步数,如果不存在方案,则输出-1。
样例输入
12345678.
123.46758
样例输出
3
样例输入
13524678.
46758123.
样例输出
22

这个题更好的办法应该是双向广搜。还没看,以后学会了再更。

这里用的是普通的广搜,需要注意的就是标记。从前简单的搜索,只用vis数组标记这个点有没有走过就行,而这个题需要标记的是状态,本以为用map可以,结果map超时,

这里我用的是字典树,练习一下。。。用vis函数标记此状态有没有经历过。

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <queue>
using namespace std;
typedef struct
{
    int step;
    char s[10];
}node;
typedef struct tnode
{
    struct tnode *next[9];
}tnode;
tnode *head = (tnode *)malloc(sizeof(tnode));
char b[10], e[10];
int dirx[4] = {1,-1,3,-3};
int vis(char a[])
{
    int flag = 1, i, j;
    tnode *root = head;
    for(i = 0 ; a[i] != '\0' ; i++)
    {
        if(root->next[a[i]-'0'] == NULL)
        {
            flag = 0;
            tnode *v = (tnode*)malloc(sizeof(tnode));
            for(j = 0 ; j < 9 ; j++)
                v->next[j] = NULL;
            root->next[a[i]-'0'] = v;
        }
        root = root->next[a[i]-'0'];  
    }
    return flag;
}
int bfs()
{
    queue<node> q;
    node u, v;
    int i, pos, vi, newpos;
    strcpy(u.s, b);
    vi = vis(u.s);
    u.step = 0;
    q.push(u);
    while(!q.empty())
    {
        u = q.front();
        q.pop();
        if(strcmp(u.s, e) == 0)
                return u.step;
        for(i = 0 ; i < 9 ; i++)
            if(u.s[i] == '0')
            {
                pos = i;
                break;
            }
        for(i = 0 ; i < 4 ; i++)
        {
            newpos = pos + dirx[i];
            if(newpos < 0 || newpos > 8)
                continue;
            if(pos % 3 == 2 && dirx[i] == 1 || pos % 3 == 0 && dirx[i] == -1)//这个必须有,在两竖边的数在进行+1-1运算时算出来的newpos虽然是在0-8之间,但是这个运算并不现实,不能从2直接到3.
				continue;
            v.step = u.step + 1;
            strcpy(v.s, u.s);
            v.s[pos] = v.s[newpos];//从前那给点变为newpos点的值,newpos变为0
            v.s[newpos] = '0';
            if(vis(v.s) == 0)
                q.push(v);
        }
    }
    return -1;
}
int main()
{
    int i;
    for(i = 0 ; i < 9 ; i++)
        head->next[i] = NULL;
    scanf("%s %s", b, e);
    if(strcmp(b, e) == 0)
    {
        printf("0\n");
        return 0;
    }
    for(i = 0 ; i < 9 ; i++)
    {
        if(b[i] == '.')
            b[i] = '0';
        if(e[i] == '.')
            e[i] = '0';
    }
    printf("%d\n", bfs());

    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值