NOJ(1571)-分支限界-8数码

描述:

在九宫格里放在1到8共8个数字还有一个是空格,与空格相邻的数字可以移动到空格的位置,问给定的状态最少需要几步能到达目标状态(用0表示空格):
1 2 3
4 5 6
7 8 0

输入:

输入一个给定的状态。

输出:

输出到达目标状态的最小步数。不能到达时输出-1。

输入样例:

1 2 34 0 67 5 8

输出样例:

2

#include<iostream>
#include<queue>
#include<map>//用map来保存状态

using namespace std;

queue <int> q1;

map <int, int> smap;//map是用来存放一组一一映射关系的,在map中,一个x只能对应一个y
//移动的四个方向
int dr[4] = {0, 1, 0, -1};
int dc[4] = {-1, 0, 1, 0};

int readdata();
int bfs();
void init(int s);
int canmoveto(int u, int dire);
int moveto(int u, int dire);

int main()
{
    int s, num;
    s = readdata();
    init(s);
    num = bfs();
    cout << num << endl;
    return (0);
}

int readdata()
{
    int i, s, num;

    s = 0;
    for(i = 0; i < 9; i++)//读取8数码的初始状态,变换成一串数保存
    {
        cin >> num;
        s = s * 10 + num;
    }
    return(s);
}

void init(int s)
{
    q1.push(s);
    smap[s] = 0;
}

int bfs()
{
    int i;
    int u, v;

    while(!q1.empty())
    {
        u = q1.front();
        q1.pop();
        for(i = 0; i < 4; i++)
        {
            if(canmoveto(u, i))
            {
                v = moveto(u, i);
                if(v == 123456780)
                {
                    return(smap[u] + 1);
                }
                if(smap.count(v) == 0)//也就是说在map/set中不存在等价的两个(以上)元素,
                    //因此某个元素在map/set中出现的次数最多只能为1,用count得到的结果不是0就是
                {
                    q1.push(v);
                    smap[v] = smap[u] + 1;//记录该条路径下的步数
                }
            }
        }
    }
    return(-1);
}

int canmoveto(int u, int dire)//编码
{
    /*用一串数来记录当前8数码的放置状态
    *在该函数中通过逆变换将8数码的位置复现在9宫格中
    *dire中保存了对0的操作方式
    *返回0移动后的合法性*/
    int i, j;
    int b[3][3];//构造9宫格
    int row, col;
    int r, c;
    int v;

    v = u;
    for(i = 2; i >= 0; i--)
    {
        for(j = 2; j >= 0; j--)
        {
            b[i][j] = v % 10;//将表示数码的数串的各位数从右往左逐个放在宫格里
            v = v / 10;
            if(b[i][j] == 0)
            {
                row = i;//记录空格的位置
                col = j;
            }
        }
    }

    r = row + dr[dire];//根据dire的值来移动空格
    c = col + dc[dire];

    if(r >= 0 && r < 3 && c >= 0 && c < 3)//约束空格移动的范围
    {
        return(1);
    }
    else
    {
        return(0);
    }
}

int moveto(int u, int dire)//解码
{
    int i, j;
    int b[3][3];
    int row, col;
    int r, c;
    int v;

    v = u;
    for(i = 2; i >= 0; i--)
    {
        for(j = 2; j >= 0; j--)
        {
            b[i][j] = v % 10;
            v = v / 10;
            if(b[i][j] == 0)
            {
                row = i;
                col = j;
            }
        }
    }

    r = row + dr[dire];
    c = col + dc[dire];

    b[row][col] = b[r][c];//交换 重新记录0在9宫格中的位置
    b[r][c] = 0;//把该位置的数值置为0

    v = 0;//将以9宫格状态存放的8数码复现成数串
    for(i = 0; i < 3; i++)
    {
        for(j = 0; j < 3; j++)
        {
            v = v * 10 + b[i][j];
        }
    }

    return(v);//返回变换后的8数码
}

总结:

  • map是用来存放一组一一映射关系的,在map中,一个x只能对应一个y
  • map.count(key)只能等于0或1,表示map容器中关键字key的个数
  • 解码和编码的过程其实可以用指针来传递相关值,减少代码量- 把每次八个数码用一个int型的9位数来保存,压缩空间
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值