首页 > 编程语言 >算法刷题笔记 八数码(C++实现)

算法刷题笔记 八数码(C++实现)

时间:2024-07-19 12:27:59浏览次数:21  
标签:状态 temp finded C++ states state 数码 position 刷题

文章目录

题目描述

  • 在一个3×3的网格中,1∼88个数字和一个x恰好不重不漏地分布在这3×3的网格中。
  • 例如:

1 2 3
x 4 6
7 5 8

  • 在游戏过程中,可以把x与其上、下、左、右四个方向之一的数字交换(如果存在)。
  • 我们的目的是通过交换,使得网格变为如下排列(称为正确排列):

1 2 3
4 5 6
7 8 x

  • 例如,示例中图形就可以通过让x先后与右、下、右三个方向的数字交换成功得到正确排列。
  • 现在,给你一个初始网格,请你求出得到正确排列至少需要进行多少次交换。

输入格式

  • 输入占一行,将3×3的初始网格描绘出来。
  • 例如,如果初始网格如下所示:

1 2 3
x 4 6
7 5 8

  • 则输入为:1 2 3 x 4 6 7 5 8

输出格式

  • 输出占一行,包含一个整数,表示最少交换次数。
  • 如果不存在解决方案,则输出−1

基本思路

  • 本题可以基于广度优先算法进行求解。对于数码的每一种摆放,我们可以将其视为一种状态,对应于一个图中的某一个结点。通过x和相邻元素的交换可以转移到另一个结点。那么,现在问题就变为,如何从开始状态的结点走到表示最终状态的结点。
  • 由于每一次x与相邻元素发生交换后的状态是可以枚举出来的,因此可以采用广度优先搜索算法进行求解。每找出一种新的状态,就记录从初始状态到当前状态所需的转换次数。

实现代码

#include <iostream>
#include <queue>
#include <unordered_set>
#include <algorithm>
using namespace std;

// 用一个结构体来定义每一个状态的数码排列和离初始状态的距离
struct digital_state
{
    string current;
    int distance;
};

const string end_state = "12345678x";

int bfs(const string& start_state)
{
    // 创建一个用于记录状态的队列,并将开始状态放入队列中
    queue<digital_state> states;
    states.push({start_state, 0});
    // 创建一个哈希集合,存储已经出现过的状态,并将开始状态放入该集合中
    unordered_set<string> finded;
    finded.insert(start_state);
    // 通过循环找出从开始状态开始的所有不同状态,并计算其距离
    while(states.empty() == false)
    {
        // 取出队首元素
        digital_state temp = states.front();
        states.pop();
        // 如果队首元素对应的状态就是最终状态,则将该状态的距离返回
        if(temp.current == end_state) return temp.distance;
        // 队首元素对应的状态不是最终状态,则查找该状态的下一个可能状态
        else
        {
            // 首先确认字符x所在的位置,并将其转换为行和列
            int x_position = temp.current.find('x');
            int x_row = x_position / 3, x_col = x_position % 3;
            
            //判定x是否可以向上移动,如果可以则找到移动后的状态
            if(x_row >= 1)
            {
                string temp_state = temp.current;
                swap(temp_state[x_position], temp_state[x_position - 3]);
                // 如果该状态还未出现过,则记录该状态
                if(finded.find(temp_state) == finded.end())
                {
                    // 将该状态放入集合中
                    finded.insert(temp_state);
                    // 将该状态放入队列中
                    states.push({temp_state, temp.distance + 1});
                }
            }
            //判定x是否可以向下移动,如果可以则找到移动后的状态
            if(x_row <= 1)
            {
                string temp_state = temp.current;
                swap(temp_state[x_position], temp_state[x_position + 3]);
                // 如果该状态还未出现过,则记录该状态
                if(finded.find(temp_state) == finded.end())
                {
                    // 将该状态放入集合中
                    finded.insert(temp_state);
                    // 将该状态放入队列中
                    states.push({temp_state, temp.distance + 1});
                }
            }
            //判定x是否可以向左移动,如果可以则找到移动后的状态
            if(x_col >= 1)
            {
                string temp_state = temp.current;
                swap(temp_state[x_position], temp_state[x_position - 1]);
                // 如果该状态还未出现过,则记录该状态
                if(finded.find(temp_state) == finded.end())
                {
                    // 将该状态放入集合中
                    finded.insert(temp_state);
                    // 将该状态放入队列中
                    states.push({temp_state, temp.distance + 1});
                }
            }
            //判定x是否可以向右移动,如果可以则找到移动后的状态
            if(x_col <= 1)
            {
                string temp_state = temp.current;
                swap(temp_state[x_position], temp_state[x_position + 1]);
                // 如果该状态还未出现过,则记录该状态
                if(finded.find(temp_state) == finded.end())
                {
                    // 将该状态放入集合中
                    finded.insert(temp_state);
                    // 将该状态放入队列中
                    states.push({temp_state, temp.distance + 1});
                }
            }
        }
    }
    // 不存在解决方案的情况
    return -1;
}

int main(void)
{
    string start_state;
    for(int i = 0; i < 9; ++ i) 
    {
        char c;
        cin >> c;
        start_state.push_back(c);
    }
    cout << bfs(start_state);
    return 0;
}

标签:状态,temp,finded,C++,states,state,数码,position,刷题
From: https://blog.csdn.net/hanmo22357/article/details/140543873

相关文章

  • C++(指针函数、函数指针)
    目录1.指针函数2.函数指针3.区别总结在C++中,指针函数和函数指针是两个不同的概念,尽管它们的名字非常相似。以下是详细的介绍和区别:1.指针函数指针函数(Pointertoafunction)是返回类型为指针的函数。它的返回值是一个指向某种数据类型的指针。以下是一个示例:int*get......
  • C++预处理器
    C++预处理器预处理器是一些指令,指示编译器在实际编译之前所需完成的预处理。所有的预处理器指令都是以井号(#)开头,只有空格字符可以出现在预处理指令之前。预处理指令不是C++语句,所以它们不会以分号(;)结尾。C++还支持很多预处理指令,比如#include、#define、#if、#else、#line......
  • 开源 C++ 框架 Ocean:用于计算机视觉和增强现实
    Facebook开源了其内部用于计算机视觉(CV)和增强现实(AR) 应用程序的框架Ocean,用于执行各种任务,包括计算机视觉、几何、媒体处理、网络和渲染。Ocean主要使用C++编写,且不依赖于特定平台:Ocean是一个独立于平台的框架,支持所有主要操作系统,包括iOS、Android、Quest......
  • C++ 函数重载注意事项
    C++中的函数重载(FunctionOverloading)是一种允许同一作用域内存在多个同名函数,但是这些函数的参数列表(参数的类型、个数或顺序)必须不同。这使得函数可以根据传入参数的不同而执行不同的任务。然而,在使用函数重载时,需要注意以下几个重要事项:参数列表必须不同:函数的参数个数、......
  • 探讨C++中巧妙的边界条件处理:以花坛种花问题为例【巧妙思想、边界条件】
    在算法题中,处理数组的边界条件是一个常见的挑战。特别是在涉及多条件判断时,如何高效且清晰地处理边界问题,可以显著提升代码的简洁性和可读性。本文将以一道经典的算法题——花坛种花问题,来探讨边界条件的巧妙处理方法。问题描述605.种花问题-力扣(LeetCode)给定一个由......
  • 百度人脸识别Windows C++离线sdk C#接入
    百度人脸识别WindowsC++离线sdkC#接入目录说明设计背景•场景特点:•客户特点:•核心需求:SDK包结构效果代码说明自己根据SDK封装了动态库,然后C#调用。功能接口设计背景•场景特点:--网络:对于无网、局域网等情况,无法连接公网,API方式无法运作。如政府单......
  • C++11 包装器
    前文C++11lambda表达式-CSDN博客C++11新的类功能&&可变参数模板-CSDN博客C++11右值引用和移动语义-CSDN博客function包装器1.概念        目前我们知道的可调用对象有:函数指针(类型定义太复杂),仿函数对象(要定义一个类,用的时候有点麻烦,不适合做类型统一),lam......
  • 初识c++:类和对象(4)
    本文大纲:1.再探构造函数(1)之前我们实现构造函数时,初始化成员变量主要使⽤函数体内赋值,构造函数初始化还有⼀种⽅式,就是初始化列表,初始化列表的使⽤⽅式是以⼀个冒号开始,接着是⼀个以逗号分隔的数据成员列表,每个"成员变量"后⾯跟⼀个放在括号中的初始值或表达式。(初始化列表......
  • C++基础-引用详解(全网最详细,看这篇就够了)
    目录前言一、引用的概念二、引用的特性三、常引用四、引用的使用场景4.1引用做参数4.2引用做返回值五、传值、传引用效率比较5.1值和引用的作为返回值类型的性能比较5.2值和引用作为参数传递之间的性能差别六、引用和指针的区别结束语前言本节我们正式进入C++......
  • 【C++】内联函数
    目录前言一、内联函数的概念二、内联函数的特征三、总结:四、如何在vs2022查看反汇编以及debug模式下查看inline反汇编需要调整的配置。4.1查看反汇编4.1debug模式下查看inline反汇编需要调整的配置结尾前言各位友友好,我们又见面了!本节我们将进入C++基......