Bootstrap

我的创作纪念日

机缘

提示:可以和大家分享最初成为创作者的初心


机缘

我最初成为创作者的初心来源于对编程的热爱和分享的渴望。作为一名计算机专业的学生,我参与过一些实际项目和竞赛,积累了不少经验,而每一次完成一个项目、解决一个难题时的成就感也促使我希望把这些经验分享出来。通过创作,我不仅能够记录日常学习和实战项目中的思考过程,还可以通过文章交流技术,帮助其他在编程道路上遇到类似问题的人。比如,在编写前端开发技巧、数据结构优化或者算法实现的文章时,我都会格外投入,因为这些不仅能提升自己的表达能力,也有助于加深对知识的理解。

收获

在创作的过程中,我收获了许多温暖的关注。比如,目前大约有240位粉丝在关注我的更新,每当看到他们的赞和评论,我都非常高兴。有一次,一篇介绍双向广度优先搜索的文章获得了309次点赞、7次评论和24407次阅读量。这些积极的反馈和互动让我更有动力去分享自己的学习心得,也让我认识到很多志同道合的编程爱好者。通过交流,我结识了不少在算法、数据分析和前端开发等领域的优秀同行,我们彼此学习,共同成长。


日常

如今,创作已经成了我生活的一部分。我发现,每当学习或完成新的编程任务时,都会产生一种强烈的想法,把这些过程和方法分享给更多人。在有限的时间和精力下,我会在每晚编程后,将其中的亮点和技巧记录下来,稍作整理后发布成文章。这样不仅提升了自己的表达和总结能力,还能时常回顾这些点滴,找到进步的方向。


成就

提示:你过去写得最好的一段代码是什么? 请用代码块贴出来
例如:

  1. 某个解题代码
    ​
    #include <string>       
    #include <iostream>    
    #include <cstdio>       
    #include <queue>        
    #include <vector>      
    #include <cstring>      // 包含 C 风格字符串处理
    #include <algorithm>    // 包含常用算法
     
    using namespace std;    // 使用标准命名空间
     
    const int maxn = 5e5 + 10; // 定义最大状态数量
    int vis[maxn]; // 定义正向搜索访问标记数组
    int vis2[maxn]; // 定义反向搜索访问标记数组
    char d[10] = { "udlr" }, d2[10] = { "durl" }; // 定义移动方向字符数组
    int dir[4] = { -3, 3, -1, 1 }; // 定义方向对应的索引变化量
    int ha[9] = { 40320, 5040, 720, 120, 24, 6, 2, 1, 1 }; // 阶乘预处理数组,用于计算哈希值
    string a, b = "123456780"; // 定义初始状态和目标状态字符串
     
    // 记录节点信息的结构体
    struct node {
        int num; // 当前节点编号
        char ch; // 从父节点到当前节点的移动方向
    } pre[maxn]; // 定义节点信息数组
     
    // 用于存储状态及其编号的结构体
    struct node2 {
        int num; // '0'所在的位置
        string s; // 状态字符串
    } e; // 定义初始状态结构体
     
    // 递归输出解法路径
    void show(int x) {
        if (pre[x].num == -1) // 如果是初始节点,返回
            return;
        show(pre[x].num); // 递归输出前一个节点
        printf("%c", pre[x].ch); // 输出当前节点的移动方向
    }
     
    // 计算状态的哈希值
    int getha(string s) {
        int sum = 0; // 初始化哈希值
        for (int i = 0; i < 9; i++) { // 遍历字符串
            int k = 0; // 逆序数计数
            for (int j = i + 1; j < 9; j++) { // 计算逆序数
                if (s[j] < s[i]) k++;
            }
            sum += k * ha[i]; // 计算哈希值
        }
        return sum; // 返回哈希值
    }
     
    // 广度优先搜索,包含双向搜索
    void bfs() {
        int q = getha(e.s); // 计算初始状态的哈希值
        queue<node2> q1; // 定义正向搜索队列
        queue<node2> q2; // 定义反向搜索队列
        vis[q] = 1; // 标记初始状态已访问
        node2 f, g; // 定义状态结构体
        f.s = b; // 设置目标状态
        f.num = 8; // 设置'0'的位置
        int p = getha(f.s); // 计算目标状态的哈希值
        int x, k; // 定义临时变量
        vis2[p] = 2; // 标记目标状态已访问
        pre[1].num = -1; // 初始化路径记录
        pre[2].num = -1; // 初始化路径记录
        int num = 2; // 设置状态编号初始值
        q1.push(e); // 初始状态入队
        q2.push(f); // 目标状态入队
        while (!q1.empty() && !q2.empty()) { // 如果两个队列都不为空
            f = q1.front(); // 取出正向搜索队列的队首元素
            q1.pop(); // 弹出队首元素
            p = getha(f.s); // 计算当前状态的哈希值
            if (vis2[p]) { // 如果反向搜索已访问
                show(vis[p]); // 输出正向路径
                k = vis2[p]; // 取出反向路径起点
                while (pre[k].num != -1) { // 输出反向路径
                    printf("%c", pre[k].ch); // 输出方向字符
                    k = pre[k].num; // 取下一个节点
                }
                printf("\n"); // 输出换行
                return; // 结束搜索
            }
            for (int i = 0; i < 4; i++) { // 遍历四个方向
                if (i == 0 && f.num < 3) continue; // 如果不能向上移动,跳过
                if (i == 1 && f.num > 5) continue; // 如果不能向下移动,跳过
                if (i == 2 && f.num % 3 == 0) continue; // 如果不能向左移动,跳过
                if (i == 3 && f.num % 3 == 2) continue; // 如果不能向右移动,跳过
                x = f.num + dir[i]; // 计算移动后的'0'位置
                g = f; // 复制当前状态
                swap(g.s[f.num], g.s[x]); // 交换'0'与目标位置
                q = getha(g.s); // 计算新状态的哈希值
                if (vis[q]) continue; // 如果新状态已访问,跳过
                vis[q] = ++num; // 标记新状态已访问,并记录编号
                g.num = x; // 更新'0'的位置
                pre[num].num = vis[p]; // 记录路径信息
                pre[num].ch = d[i]; // 记录移动方向
                q1.push(g); // 新状态入队
            }
            f = q2.front(); // 取出反向搜索队列的队首元素
            q2.pop(); // 弹出队首元素
            p = getha(f.s); // 计算当前状态的哈希值
            if (vis[p]) { // 如果正向搜索已访问
                show(vis[p]); // 输出正向路径
                k = vis2[p]; // 取出反向路径起点
                while (pre[k].num != -1) { // 输出反向路径
                    printf("%c", pre[k].ch); // 输出方向字符
                    k = pre[k].num; // 取下一个节点
                }
                printf("\n"); // 输出换行
                return; // 结束搜索
            }
            for (int i = 0; i < 4; i++) { // 遍历四个方向
                if (i == 0 && f.num < 3) continue; // 如果不能向上移动,跳过
                if (i == 1 && f.num > 5) continue; // 如果不能向下移动,跳过
                if (i == 2 && f.num % 3 == 0) continue; // 如果不能向左移动,跳过
                if (i == 3 && f.num % 3 == 2) continue; // 如果不能向右移动,跳过
                x = f.num + dir[i]; // 计算移动后的'0'位置
                g = f; // 复制当前状态
                swap(g.s[f.num], g.s[x]); // 交换'0'与目标位置
                q = getha(g.s); // 计算新状态的哈希值
                if (vis2[q]) continue; // 如果新状态已访问,跳过
                vis2[q] = ++num; // 标记新状态已访问,并记录编号
                g.num = x; // 更新'0'的位置
                pre[num].num = vis2[p]; // 记录路径信息
                pre[num].ch = d2[i]; // 记录移动方向
                q2.push(g); // 新状态入队
            }
        }
        printf("unsolvable\n"); // 如果队列为空,输出 unsolvable
    }
     
    int main() {
        while (getline(cin, a)) { // 读取输入行
            int n, k = 0; // 定义字符串长度和逆序数计数器
            n = a.size(); // 获取输入字符串长度
            e.s = ""; // 初始化状态字符串
            for (int i = 0, j = 0; i < n; i++) { // 遍历输入字符串
                if (a[i] != ' ') { // 如果不是空格
                    if (a[i] == 'x') { // 如果是'x'
                        e.num = j; // 记录'0'的位置
                        e.s += '0'; // 将'x'转换为'0'
                    } else {
                        e.s += a[i]; // 添加字符到状态字符串
                    }
                    j++; // 字符计数器加1
                }
            }
            for (int i = 0; i < 9; i++) { // 遍历状态字符串
                if (e.s[i] == '0') continue; // 如果是'0'跳过
                for (int j = 0; j < i; j++) { // 计算逆序数
                    if (e.s[j] == '0') continue; // 如果是'0'跳过
                    if (e.s[j] > e.s[i]) k++; // 如果前面的数比当前数大,逆序数加1
                }
            }
            memset(vis2, 0, sizeof(vis2)); // 重置反向访问标记数组
            memset(vis, 0, sizeof(vis)); // 重置正向访问标记数组
            if (k & 1) { // 如果逆序数为奇数
                printf("unsolvable\n"); // 输出 unsolvable
            } else {
                bfs(); // 否则进行广度优先搜索
            }
        }
        return 0; // 程序结束
    }
     
    ​

憧憬

在未来的职业规划中,我希望能进一步拓展在算法与数据结构方面的专业知识,并在某天成为技术社区中的一名受欢迎的创作者。

;