八数码问题(bfs广度优先搜索)

最近在学bfs,觉得这个题不错,自己没做出来,去网上搜了一下,又结合了我自己的想法,ac了;

这个看起来用dfs比较好做,但是会超时好像,所以肯定用bfs了。

问题描述

  在九宫格里放在1到8共8个数字还有一个是x,与x相邻的数字可以移动到x的位置,问给定的状态最少需要几步能到达目标状态:

  1 2 3

       4 5 6

       7 8 x

输入

  输入一个初始状态;

输出

  到达目标状态所需要的最少步数;

样例

  输入:

    1 2 3

    x 4 6

    7 5 8

  输出:

    19

思路:

  首先,可以根据输入的初始状态直接判断此题是否有解,无解的情况直接输出-1就ok了;

  具体方法是:将输入的九个数存到一个一维数组,假设f(1)为数字1在数组位置中在1前面比1小的数,

  f(2)为数字2在数组位置中,在2前面比2小的数,.........,直到f(8),将f(1)+f(2).....到f(8)的值相加,

  如果得到的数是偶数则有解,奇数则无解。

  然后,将每个状态的九宫格替换成一个整数表示,例如样例 123046758,x替换成0,然后用map,来存储状态是否被     访问过,这样只需遍历0所在位置可以移动的方向,如果没有出界的话,求出移动后的九宫格状态,压入队列中,直到目标解,返回最少步数。具体实现请看代码。

ac代码:

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<cstdio>
  6 #include<queue>
  7 #include<map>
  8 #define inf 0x3f3f3f3f
  9 using namespace std;
 10 const int N = 10000 + 10;
 11 int dx[] = { 1,-1,0,0 };
 12 int dy[] = { 0,0,1,-1 };
 13 
 14 int a[5][5], d[10];
 15 map<int, int>vis;  //存储九宫格状态是否被访问过
 16 map<int, int>step; //存储到达此状态所需的最少步数
 17 int px, py, lx, ly;
 18 
 19 bool check(int u, int v) {        //将九宫格换成二维数组形式,并检查移动后是否出界
 20     int r = u, x, y;
 21     for (int i = 3; i >= 1; i--) {
 22         for (int j = 3; j >= 1; j--) {
 23             a[i][j] = r % 10;
 24             r /= 10;
 25             if (a[i][j] == 0) {
 26                 lx = i, ly = j;
 27                 px = i + dx[v], py = j + dy[v];
 28                 //cout << x << " " << y;
 29             }
 30             //cout << a[i][j] << " ";
 31         }
 32         //cout << "\n";
 33     }
 34     //cout << "\n";
 35     
 36     if (px >= 1 && px <= 3 && py >= 1 && py <= 3) {
 37         return true;
 38     }
 39     else return false;
 40 }
 41 
 42 int move_to(int ax, int ay, int bx, int by) {   //求解移动后的九宫格状态
 43     //cout << "...";
 44     a[ax][ay] = a[bx][by];
 45     a[bx][by] = 0;
 46     int val = 0;
 47     for (int i = 1; i <= 3; i++) {
 48         for (int j = 1; j <= 3; j++) {
 49             val = val * 10 + a[i][j];
 50         }
 51     }
 52     return val;
 53 }
 54 
 55 int bfs(int k) {        //bfs求最少步数
 56     queue<int>q;
 57     q.push(k);
 58     vis[k] = 1;
 59     step[k] = 0;
 60     while (!q.empty()) {
 61         int t = q.front();
 62         //cout << t << "\n";
 63         q.pop();
 64         int r = t, x = 0, y = 0;
 65         if (t == 123456780) {    //如果到达返回最少步数
 66             return step[t];
 67         }
 68         for (int i = 0; i < 4; i++) {
 69             //int px = x + dx[i];
 70             //int py = y + dy[i];
 71             //cout << px << " " << py << "\n";
 72             //cout << "...";
 73             if (check(t, i)) {
 74                 int pos_now = move_to(lx, ly, px, py);
 75                 //cout << pos_now << "ppp" << "\n";
 76                 if (!vis[pos_now]) {
 77                     /*for (int i = 1; i <= 3; i++) {
 78                         for (int j = 1; j <= 3; j++) {
 79                             cout << a[i][j] << " ";
 80                         }
 81                         cout << "\n";
 82                     }*/
 83                     //cout << "\n";
 84                     vis[pos_now] = 1;
 85                     step[pos_now] = step[t] + 1;
 86                     q.push(pos_now);
 87                 }
 88             }
 89         }
 90     }
 91     return 0;
 92 }
 93 
 94 int main() {
 95 
 96     int x = 0, cut = 1;
 97     for (int i = 1; i <= 3; i++) {
 98         for (int j = 1; j <= 3; j++) {
 99             char ch;
100             cin >> ch;
101             if (ch == 'x') ch = '0';
102             a[i][j] = ch - '0';
103             x = x * 10 + a[i][j];
104             d[cut++] = a[i][j];
105             //cout << a[i][j] << "\n";
106         }
107     }
108     //求九宫格是否有解
109     int rem = 0;
110     for (int i = 1; i <= 9; i++) {
111         for (int j = 1; j < i; j++) {
112             if (d[j] == 0) continue;
113             if (d[i] > d[j]) rem++;
114         }
115     }
116     //cout << x << "\n";
117     if (rem % 2) {
118         cout << -1 << "\n";
119     }
120     else {
121         int ans = bfs(x);
122         if (ans) cout << ans << "\n";
123     }
124     
125     return 0;
126 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值