ACM模板笔记:八数码问题——使用BFS+康托展开打表解决

淦宁佬,能拿到蓝桥杯省二就算成功:(,ACM拿锤子奖,我这说唱专业的说唱学生百分百白给,是这样的

这只是我个人的备忘录,因为这个是刚学,所以给的注解比较详细 ,如果你能看得懂就将就看:P,实在不行去洛谷,那里大佬多的一批。

题目链接:http://poj.org/problem?id=1077
学习借鉴链接:https://www.cnblogs.com/zufezzt/p/5659276.html
判断八数码是否有解的一种方法:http://blog.sina.com.cn/s/blog_5d09995201019kjo.html
这个代码大致和之前的类似,但是按我的语法命名和数据输入习惯去改了下

#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
//用来存状态
char situcation[1000];
//用来存阶乘
int c[10];
//方向
int dir[4][2] = { {-1,0},{1,0},{0,-1},{0,1} };
//道路
string path="durl";
//检查是否遍历过
bool visit[400000];
struct Node{
    int s, pos;//数字化状态和位置
    Node() {}
    Node(int S, int P) { s = S, pos = P; }
};
//记录路径
struct Path{
    int fa, dir;//记录上级和上级的相对方向
}pa[400000];
//获得每一步的康托蛤希
int getnum(){
    int res = 0;
    for (int i = 0; situcation[i]; i++)
        for (int j = i + 1; situcation[j]; j++)
            if (situcation[j] < situcation[i]) res = res + c[8 - i];
    return res;
}
//把数字状态转化为字符串
void getstr(int val){
    int tmp[10], flag[10];
    memset(flag, 0, sizeof flag);
    for (int i = 0; i < 9; i++) {
        tmp[i] = val / c[8 - i];
        val = val % c[8 - i];
    }
    for (int i = 0; i < 9; i++){
        int num = 0;
        for (int j = 0; j < 9; j++){
            if (flag[j] == 0) 
                num++;
            if (num == tmp[i] + 1){
                situcation[i] = j + '0' + 1; 
                if (situcation[i] == '9') 
                    situcation[i] = 'x';
                flag[j] = 1; break;
            }
        }
    }
}
//提前进行打表
void pre() {
    queue<Node>Q;
    Q.push(Node(0, 8));
    visit[0] = 1; pa[0].fa = -1, pa[0].dir = -1;
    while (!Q.empty()){
        Node h = Q.front(); Q.pop();
        int a = h.pos / 3, b = h.pos % 3; 
        //将取出的点转化为一个字符串化状态
        getstr(h.s);
        for (int i = 0; i < 4; i++){
            //开始进行遍历
            int x = a + dir[i][0], y = b + dir[i][1];
            //检测范围
            if (!(x >= 0 && x <= 2 && y >= 0 && y <= 2)) continue;
            //交换
            int newpos = 3 * x + y;
            swap(situcation[newpos], situcation[h.pos]);
            int news = getnum();
            //如果遍历过了就回退状态
            if (visit[news]) { 
                swap(situcation[newpos], situcation[h.pos]); 
                continue; 
            }
            //记录它的上级
            pa[news].fa = h.s;
            //这玩意是用来记录来的方向的
            pa[news].dir = i;
            //记录是否遍历过
            visit[news] = 1;
            //记录这个转态
            Q.push(Node(news, newpos));
            //进行回退,在进行下一次遍历
            swap(situcation[newpos], situcation[h.pos]);
        }
    }


}

int main() {
	c[0] = 1; 
	for (int i = 1; i <= 8; i++) 
		c[i] = c[i - 1] * i;
    //打表,方便后面进行康托展开
    pre();
    char op; int counter = 0;
    while (cin>>op){
        situcation[counter++] = op;
    }
    int state = getnum();
    //输出
    if (visit[state] == 0) printf("unsolvable\n");
    else {
        while (1){
            if (pa[state].fa == -1) break;
            printf("%c", path[pa[state].dir]);
            state = pa[state].fa;
        }
        printf("\n");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值