双向广搜 Solitaire——hdu1401

news2024/11/24 11:07:20

目录

前言

   字符数字的转换

   bfs or double dfs

  棋局的编号

Solitaire

   问题描述

   输入

   输出

问题分析

   判重

   棋子走动逻辑

单向搜索代码

   双向搜索退出条件

   双向广搜代码


前言

        交代一下我写这题的感受,被自己气笑了,本来以为是我字符串没弄好,就总盯着字符串,结果发现连最基本的变量赋值逻辑都弄错了,服了

   字符数字的转换

                                   字符-'0' 字符变数字,数字+'0' 数字变字符

   bfs or double dfs

        这题为什么不能用bfs,其实用bfs还是用double bfs很好判断,就看一下每次入队的状态数量为多少即可

        本题总共有四个棋子,每个棋子都有上下左右四个方向,就意味着单个节点入队最多为4*4=16,种方案,不难发现,这个还是以指数形增长的,如果连续八步那么就会拓展出,16^{8}>1500万种状态,非常恐怖。

        所以要用double bfs减少状态数大约2*16^{4}=131072种棋局,具体关于double bfs分析在这里双向广搜

  棋局的编号

        本题为了方便判重,我对该棋盘的所有格子都进行了编号

12345678
910111213141516
1718192021222324
2526272829303132
3334353637383940
4142434445464748
4950515253545556
5758596061626464

例如四个棋子如果为(1,1),(1,2),(1,3),(1,4)那么我就用string s="1234"代表它

Solitaire

   问题描述

        在一个8*8的棋盘中放入四个棋子,要求八步之内四颗棋子到达指定位置,现给出四颗棋子的初始位置,和最终位置,判断是否可以到达终点

   输入

        总共两行,第一行用八个整数代表四颗棋子的初始位置,第二行用八个整数代表四颗棋子的终止位置

   输出

        如果可以到达终点,那么输出"YES",否则输出"NO"

问题分析

        前面已经说过,本题需要用到双向广搜,我们不妨先实现单向搜索

   判重

        其实这才是我想发这题的题解的原因,本题最重要的就是判重的操作,首先明确一点:绝对不能用int vis[][][][][][][][]判重,这个八位数组占用空间太大,算一下等于32^{8}=104.8576GB,会爆掉

所以次优先的方法就是改用char数组那么就可以减到8^{8}=16MB,勉强可以接受。但如果把这个八位数砍成一个字符串,用map压缩无效空间,那么这个内存占用将会减少到几kb

   棋子走动逻辑

        题目说棋子可以上下左右移动,如果碰到该方向有棋子,那么就往该方向再移动一格(这个操作最多一次),根据代码逻辑就可以编写代码

nx += dir[k][0];
ny += dir[k][1];
if (!check(nx, ny, i,now.s)) {
    nx +=dir[k][0];
    ny +=dir[k][1];
    if (!check(nx, ny, i,now.s)) { //如果还有棋子,continue
        continue;
    }
}

        check函数:

//这个字符串索引逻辑可以参考上图
bool check(int x,int y,int i,string s) {
    for(int k=0;k<4;k++){
        if (k != i) {
            if (x == (s[2*k]-'0') && y == (s[2*k + 1]-'0') ) {
                return false;
            }
        }
    }
    return true;
}

        translate函数

                这个是将棋子位置转化为一个独一无二的字符串(方便判重)的代码

string Translate(string s) {

    vector<int> pos(4);
    for (int i = 0; i < 4; i++) {
        // 将每两位字符转换为一个十进制数
        // 注意:这里假设输入字符串只包含'0'和'1',且长度至少为8
        pos[i] = ((s[2 * i] - '0')-1) * 8 + (s[2 * i + 1] - '0');
    }

    sort(pos.begin(), pos.end());

    string a;
    for (int i = 0; i < 4; i++) {
        // 将排序后的十进制数转换回字符串,并拼接到结果字符串中
        a += to_string(pos[i]);
    }

    return a;
}

   单向搜索代码

#include<string>
#include<iostream>
#include<map>
#include<queue>
#include<algorithm>
using namespace std;
int dir[4][2] = { {0,-1},{0,1},{1,0},{-1,0} };
struct node {
    string s;
    int step;
    node() {}
    node(string ss,int ste):s(ss),step(ste){}
};
map<string, bool>vis;
queue<node>que;
int pos[4];
string m;
string st, ed;
string ed_s;
string st_s;
node now, nxt;
bool flag=false;

string Translate(string s) {

    vector<int> pos(4);
    for (int i = 0; i < 4; i++) {
        // 将每两位字符转换为一个十进制数
        // 注意:这里假设输入字符串只包含'0'和'1',且长度至少为8
        pos[i] = ((s[2 * i] - '0')-1) * 8 + (s[2 * i + 1] - '0');
    }

    sort(pos.begin(), pos.end());

    string a;
    for (int i = 0; i < 4; i++) {
        // 将排序后的十进制数转换回字符串,并拼接到结果字符串中
        a += to_string(pos[i]);
    }

    return a;
}

bool check(int x,int y,int i,string s) {
    for(int k=0;k<4;k++){
        if (k != i) {
            if (x == (s[2*k]-'0') && y == (s[2*k + 1]-'0') ) {
                return false;
            }
        }
    }
    return true;
}

void bfs() {
    que.push(node(st, 0));
    m=Translate(st);
    vis[m] = true;
    while (!que.empty()) {
        now = que.front();
        que.pop();
        for(int i=0;i<4;i++){
            //一开始把这行放这了,我是真的服了
            //int nx = int(now.s[2*i] - '0'), ny = int(now.s[2*i + 1] - '0');
            for (int k = 0; k < 4; k++) {
                int nx = int(now.s[2*i] - '0'), ny = int(now.s[2*i + 1] - '0');
                nx += dir[k][0];
                ny += dir[k][1];
                if (!check(nx, ny, i,now.s)) {
                    nx +=dir[k][0];
                    ny +=dir[k][1];
                    if (!check(nx, ny, i,now.s)) {
                        continue;
                    }
                }
                if (nx < 1 || nx > 8 || ny < 1 || ny > 8) continue;
                nxt.s = now.s;
                nxt.s[2*i] = '0'+nx;
                nxt.s[2*i + 1] = '0'+ny;
                nxt.step = now.step + 1;        
                if (nxt.step > 8) continue;
                m = Translate(nxt.s);
                if (nxt.step <= 8 && m == ed_s) {
                    flag = true;
                    return;
                }
                if (!vis[m]) {
                    vis[m] = true;
                    que.push(nxt);
                }
            }
        }
    }
}

//注:字符-'0' 字符变数字,数字+'0' 数字变字符
int main() {
    int i, j;
    for (int k = 1; k <= 8; k++) {
        cin >> i;
        st += '0'+i;
    }
    for (int k = 1; k <= 8; k++) {
        cin >> j;
        ed += '0'+j;
    }
    st_s = Translate(st);
    ed_s = Translate(ed);
    if (st_s == ed_s) {
        cout << "YES" << endl;
        return 0;
    }
    bfs();
    if (flag) {
        cout << "YES" << endl;
    }
    else {
        cout << "NO" << endl;
    }
    return 0;
}

        接下来我们就把它改为双向搜索代码

   双向搜索退出条件

        双向搜索是起点和终点同时同速度出发搜索,那么他们相遇的时候所走的路程一定相同,要求总步数不大于8,那么每个人走的步数也要不大于4,此外我们定义了一个visa判重1代表起点搜过,2代表终点搜过,如果每一个队列搜到了另一个队列的标记,那么也代表他们相遇了

        顺嘴提一句,那个if (nxt.step > 8) continue;的剪枝8也要改成4

   双向广搜代码

#include<string>
#include<iostream>
#include<map>
#include<queue>
#include<algorithm>
using namespace std;
int dir[4][2] = { {0,-1},{0,1},{1,0},{-1,0} };
struct node {
    string s;
    int step;
    node() {}
    node(string ss,int ste):s(ss),step(ste){}
};
map<string, int>vis;
queue<node>qa;
queue<node>qb;
int pos[4];
string m;
string st, ed;
string ed_s;
string st_s;
node now, nxt;
bool flag=false;

string Translate(string s) {
    vector<int> pos(4);
    for (int i = 0; i < 4; i++) {
        pos[i] = ((s[2 * i] - '0')-1) * 8 + (s[2 * i + 1] - '0');
    }
    sort(pos.begin(), pos.end());
    string a;
    for (int i = 0; i < 4; i++) {
        // 将排序后的十进制数转换回字符串,并拼接到结果字符串中
        a += to_string(pos[i]);
    }
    return a;
}

bool check(int x,int y,int i,string s) {
    for(int k=0;k<4;k++){
        if (k != i) {
            if (x == (s[2*k]-'0') && y == (s[2*k + 1]-'0') ) {
                return false;
            }
        }
    }
    return true;
}

void dul_bfs() {
    qa.push(node(st, 0));
    qb.push(node(ed, 0));
    vis[st_s] = 1;
    vis[ed_s] = 2;
    while (!qa.empty() && !qb.empty()) {
        if (qa.size() < qb.size()) {
            now = qa.front();
            qa.pop();
            for(int i=0;i<4;i++){
                for (int k = 0; k < 4; k++) {
                    int nx = now.s[2*i] - '0', ny = now.s[2*i + 1] - '0';
                    nx += dir[k][0];
                    ny += dir[k][1];
                    if (!check(nx, ny, i,now.s)) {
                        nx +=dir[k][0];
                        ny +=dir[k][1];
                        if (!check(nx, ny, i,now.s)) {
                            continue;
                        }
                    }
                    if (nx < 1 || nx > 8 || ny < 1 || ny > 8) continue;
                    nxt.s = now.s;
                    nxt.s[2*i] = '0'+nx;
                    nxt.s[2*i + 1] = '0'+ny;
                    nxt.step = now.step + 1;        
                    if (nxt.step > 4) continue;
                    m = Translate(nxt.s);
                    if (nxt.step <= 4 && vis[m]==2) {
                        flag = true;
                        return;
                    }
                    if (!vis[m]) {
                        vis[m] = 1;
                        qa.push(nxt);
                    }
                }
            }
        }
        else {
            now = qb.front();
            qb.pop();
            for (int i = 0; i < 4; i++) {
                for (int k = 0; k < 4; k++) {
                    int nx = now.s[2 * i] - '0', ny = now.s[2 * i + 1] - '0';
                    nx += dir[k][0];
                    ny += dir[k][1];
                    if (!check(nx, ny, i, now.s)) {
                        nx += dir[k][0];
                        ny += dir[k][1];
                        if (!check(nx, ny, i, now.s)) {
                            continue;
                        }
                    }
                    if (nx < 1 || nx > 8 || ny < 1 || ny > 8) continue;
                    nxt.s = now.s;
                    nxt.s[2 * i] = '0' + nx;
                    nxt.s[2 * i + 1] = '0' + ny;
                    nxt.step = now.step + 1;
                    if (nxt.step > 4) continue;
                    m = Translate(nxt.s);
                    if (nxt.step <= 4 && vis[m]==1) {
                        flag = true;
                        return;
                    }
                    if (!vis[m]) {
                        vis[m] = 2;
                        qb.push(nxt);
                    }
                }
            }
        }
        
    }
}

//注:字符-'0' 字符变数字,数字+'0' 数字变字符
int main() {
    int i, j;
    for (int k = 1; k <= 8; k++) {
        cin >> i;
        st += '0'+i;
    }
    for (int k = 1; k <= 8; k++) {
        cin >> j;
        ed += '0'+j;
    }
    st_s = Translate(st);
    ed_s = Translate(ed);
    if (st_s == ed_s) {
        cout << "YES" << endl;
        return 0;
    }
    dul_bfs();
    if (flag) {
        cout << "YES" << endl;
    }
    else {
        cout << "NO" << endl;
    }
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2209153.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JAVA——File类

目录 1.概述 2.构造方法 a.根据文件路径创建文件对象 b.根据父级路径和子级路径创建对象 c.根据File表示的路径和String表示路径进行拼接 3.常见方法 a.判断文件是否存在 b.判断文件是否为文件夹 c.判断是否为文件 d.获取文件大小 e.获取文件的绝对路径 f.获取定义…

Apache Kafka基础认知-Part1

微信公众号&#xff1a;阿俊的学习记录空间小红书&#xff1a;ArnoZhangwordpress&#xff1a;arnozhang1994博客园&#xff1a;arnozhangCSDN&#xff1a;ArnoZhang1994 Apache Kafka 是一个分布式流处理平台&#xff0c;具备以下三大核心功能&#xff1a; 记录流的发布和订…

Java项目: 基于SpringBoot+mybatis+maven+vue共享汽车管理系统(含源码+数据库+开题报告+毕业论文)

一、项目简介 本项目是一套基于SpringBootmybatismavenvue共享汽车管理系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操…

持续领先,从IDC报告看联想企业级全栈能力如何加速智能化转型

作者 | 曾响铃 文 | 响铃说 如果问智能化转型浪潮中&#xff0c;哪个行业受到的关注最多&#xff1f;毫无疑问&#xff0c;与产业升级、宏观导向密切相关的制造业一定会是答案之一&#xff0c;智能制造已经成为普遍共识。 这其中&#xff0c;面向制造业的智能化基础设施承担…

PHP 学生成绩在线发布系统-计算机毕业设计源码81780

摘 要 计算机科学技术的飞速发展也更好地促进了高校信息化建设。为了适应新形势下更好地培养人才&#xff0c;高校在发展的过程中开始推进信息系统的建设。随着我国教育模式的不断改革和发展&#xff0c;越来越多的高校正在开展校园信息工程建设&#xff0c;以更好地提高高校…

dy弹幕 新版abogus 180+长度 signature分析

声明: 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 有相关问题请第一时间头像私信联系我删…

初始操作系统篇(2)—— 操作系统的运行环境与体系结构

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a; 操作系统 目录 操作系统的运行环境 操作系统的运行机制 中断 系统调用 操作系统的体系结构 大内核 微内核 优点 缺点 操作系统的运行…

PostgreSql的备份和升级

目录 版本概述&#xff1a; 跨大版本数据迁移 QProcess 调用相关进程进行备份和恢复 版本概述&#xff1a; 该数据库版本主要分为主要版本和次要版本&#xff0c;大版本基本每年发布一次&#xff0c;小版本则每几个月即发布&#xff0c;更新较快。在10.0之前所使用的数据库版…

YOLOv11全网最新创新点改进系列:一文读懂YOLOv11算法!!!

YOLOv11全网最新创新点改进系列&#xff1a;免费送&#xff01;&#xff01;&#xff01;改进且跑通的源码&#xff01;&#xff01;融入CBAM注意力&#xff0c;将通道注意力和空间注意力相结合&#xff0c;嘎嘎提升V11算法&#xff0c;叫叫首&#xff0c;改进速度遥遥领先&…

字符串拼接方法性能对比和分析

对字符串进行拼接主要有三种方法&#xff1a; 1.加号 2.concat方法 3.StringBuilder或者StringBuffer的append方法 下面看下性能对比&#xff0c;测试方法为各循环十万次&#xff0c;对比耗费时间。 测试性能 1.”"拼接 long start System.currentTimeMillis();String …

如何通过钢筋计来优化施工安全

在现代建筑工程中&#xff0c;施工安全一直是首要关注的问题。特别是在高层建筑、桥梁和地下工程等复杂结构中&#xff0c;确保钢筋的正确安装和稳定性能&#xff0c;直接关系到工程的整体安全性和耐久性。钢筋计作为一种专门用于测量和监测钢筋应力和应变的设备&#xff0c;其…

信号完整性分析概论

随着时钟频率的提高&#xff0c;发现并解决信号完整性问题成为产品开发的关键。成功的秘诀是精通信号完整性分析技术&#xff0c;并能采取高效设计过程以消除这些问题。只有熟地运用新的设计规则、新的技术和新的分析工具&#xff0c;才能实现高性能设计&#xff0c;并日益缩短…

第二份代码:PointNet++

参考的依然是Pytorch的实现&#xff0c;PointNet里面的主要实现部分都在utils.py里&#xff0c;里面从微小模块逐渐的&#xff0c;搭建出网络中的几个主要模块结构&#xff0c;包括sampling&group等&#xff0c;所以我们主要分析的就是这个utils.py里面的内容 这份Pytorch实…

PE结构之绑定导入表

打印绑定导入表 //打印 绑定导入表 BOOL PrintBoundImport(__in char* m_fileName) {char* Filebuffer NULL;if (!GetFileBuffer(m_fileName, &Filebuffer)) return FALSE;PIMAGE_DOS_HEADER LPdosHeader NULL;PIMAGE_NT_HEADERS LPntHeader NULL;LPdosHeader (PIMAGE…

LLM | Tokenization 从原理与代码了解GPT的分词器

声明&#xff1a;以上内容全是学习Andrej Karpathy油管教学视频的总结。 --------------------------------------------------------------------------------------------------------------------------------- 大家好。在今天我们学习llm中的Tokenization&#xff0c;即分…

快收藏!超实用标签title属性重写,让同事对你刮目相看

原生title属性的弊端 日常开发中&#xff0c;我们经常会遇到hover文本&#xff0c;显示其全部内容的需求。但是原生的title属性有两个很大的缺点 样式丑陋&#xff0c;无法更改 windows下的样式 mac下的样式 不够智能&#xff0c;属性显影只能人为控制 只要写了title属性&a…

使用Provide和Inject设计Vue3插件

使用provide和inject的Vue依赖项注入非常适合构建Vue3插件或避免prop多层传递。 尽管不经常使用它&#xff0c;但是您可以仅使用两个内置方法来实现依赖项注入&#xff1a;provide和inject。 查看Composition API文档&#xff0c;在Vue 3.0中&#xff0c;使用Provide和Inject进…

【笔记】Day2.5.1查询运费模板列表(未完

&#xff08;一&#xff09;代码编写 1.阅读需求&#xff0c;确保理解其中的每一个要素&#xff1a; 获取全部运费模板&#xff1a;这意味着我需要从数据库中查询所有运费模板数据。按创建时间倒序排序&#xff1a;这意味着查询结果需要根据模板的创建时间进行排序&#xff0…

汉语言文学做大数据七年实际工作经验分享普通人快来围观

&#xff08;一&#xff09;没有人带你 社会上&#xff0c;都很现实。就是进了公司&#xff0c;有师傅&#xff0c;师傅也没空带你&#xff0c;最多就是有空的时候帮你解决问题。 无论是做啥工作&#xff0c;都要靠自己努力。努力不会成为笑话&#xff0c;不努力就是笑话。就…

Crypto虐狗记---”你“和小鱼(五)

前言&#xff1a;剧情五 提示&#xff1a; 一种食物&#xff1f; 一种食物——培根&#xff1a;&#xff08;A B 也暗示是培根加密&#xff09; cyberpeace{attackanddefenceworldisinteresting} 密码学笔记——培根密码 - ILK - 博客园 (cnblogs.com)