人工智能原理实验二:搜索方法

一、实验目的

本实验课程是计算机、智能、物联网等专业学生的一门专业课程,通过实验,帮助学生更好地掌握人工智能相关概念、技术、原理、应用等;通过实验提高学生编写实验报告、总结实验结果的能力;使学生对智能程序、智能算法等有比较深入的认识。

  1. 掌握人工智能中涉及的相关概念、算法。
  2. 熟悉人工智能中的知识表示方法;
  3. 熟悉盲目搜索和启发式搜索算法的应用;
  4. 掌握问题表示、求解及编程实现。
  5. 掌握不同搜索策略的设计思想、步骤、性能。

二、基本要求

1、实验前,复习《人工智能》课程中的有关内容。

2、准备好实验数据。

3、编程要独立完成,程序应加适当的注释。

4、完成实验报告。

三、实验软件

使用C或C++(Visual studio)(不限制语言使用)。

四、实验内容:

(1)

1、在图1,3*3的方格棋盘上,摆放着1到8这八个数码,有1个方格是空。

2、如图1所示,要求对空格执行空格左移、空格右移、空格上移和空格下移这四个操作使得棋盘从初始状态(图1左)到目标状态(图1右)。

3、可自行设计初始状态。目标状态为数字从小到大按顺时针排列。

4、分别用广度优先搜索策略、深度优先搜索策略和启发式搜索算法(A*算法)求解八数码问题;分析估价函数对启发式搜索算法的影响;探究各个搜索算法的特点。

 

(2)罗马尼亚问题

根据上图以Zerind为初始状态,Bucharest为目标状态实现搜索,分别以贪婪搜索(只考虑直线距离)和A*算法求解最短路径。 按顺序列出贪婪算法探索的扩展节点和其估价函数值,A*算法探索的扩展节点和其估计值。

选做部分:自行设计一个新的启发式函数,并分析该函数的可采纳性和优势(与启发式函数定义为“Zerind到Bucharest的直线距离”相比较)。

五、学生实验报告要求

1、实验报告需要包含以下几个部分

(1)状态表示的数据结构

实验一:

struct State {
    int puzzle[3][3];
    int cost;  // 从起始状态到当前状态的代价
    int heuristic;  // 启发式估计的代价
};

结构体包含一个3x3的整数数组 puzzle 表示八数码的状态,以及两个整数 cost 和 heuristic 分别表示从起始状态到当前状态的代价和启发式估计的代价。

实验二:

状态使用图(city_graph)和字典(to_B_distance)表示。图(city_graph)是一个列表的列表,其中每个内部列表表示两个城市之间的边以及相应的距离。字典(to_B_distance)存储每个城市到目标城市 'B' 的直线距离。起始城市和结束城市分别定义为 'start_city' 和 'end_city'。

(2)状态扩展规则的表示

状态扩展规则在 greedy 和 A_plus 函数中表示。这些函数基于特定的准则探索相邻城市。对于贪婪算法,它选择距离目标最近的城市。在A*算法中,考虑总成本函数 f(x) = g(x) + h(x),其中 g(x) 是从开始到当前节点的成本,h(x) 是启发式(到目标的直线距离)

(3)搜索产生的状态空间图

八数码:

罗马尼亚问题:

(4)OPEN表和CLOSE表变化过程

Expnd.node

Open list

{Z}

Z

{O,A}

A

{S,T}

S

{R,F}

R

{P,C}

P

{C,B}

B(goal)

{G,U}

(5)程序清单

实验(1)

#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>

using namespace std;

// 表示八数码状态的结构体
struct State {
    int puzzle[3][3];
    int cost;  // 从起始状态到当前状态的代价
    int heuristic;  // 启发式估计的代价
};

// 定义操作:空格左移、右移、上移、下移
State moveLeft(const State& s) {
    State newState = s;
    int emptyRow, emptyCol;
    // 找到空格的位置
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            if (s.puzzle[i][j] == 0) {
                emptyRow = i;
                emptyCol = j;
                break;
            }
        }
    }
    // 左移操作,交换空格和左侧数字的位置
    if (emptyCol > 0) {
        swap(newState.puzzle[emptyRow][emptyCol], newState.puzzle[emptyRow][emptyCol - 1]);
    }
    return newState;
}

State moveRight(const State& s) {
    State newState = s;
    int emptyRow, emptyCol;
    // 找到空格的位置
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            if (s.puzzle[i][j] == 0) {
                emptyRow = i;
                emptyCol = j;
                break;
            }
        }
    }
    // 右移操作,交换空格和右侧数字的位置
    if (emptyCol < 2) {
        swap(newState.puzzle[emptyRow][emptyCol], newState.puzzle[emptyRow][emptyCol + 1]);
    }
    return newState;
}

State moveUp(const State& s) {
    State newState = s;
    int emptyRow, emptyCol;
    // 找到空格的位置
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            if (s.puzzle[i][j] == 0) {
                emptyRow = i;
                emptyCol = j;
                break;
            }
        }
    }
    // 上移操作,交换空格和上方数字的位置
    if (emptyRow > 0) {
        swap(newState.puzzle[emptyRow][emptyCol], newState.puzzle[emptyRow - 1][emptyCol]);
    }
    return newState;
}

State moveDown(const State& s) {
    State newState = s;
    int emptyRow, emptyCol;
    // 找到空格的位置
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            if (s.puzzle[i][j] == 0) {
                emptyRow = i;
                emptyCol = j;
                break;
            }
        }
    }
    // 下移操作,交换空格和下方数字的位置
    if (emptyRow < 2) {
        swap(newState.puzzle[emptyRow][emptyCol], newState.puzzle[emptyRow + 1][emptyCol]);
    }
    return newState;
}

// 检查两个状态是否相等
bool isEqual(const State& s1, const State& s2) {
    return memcmp(s1.puzzle, s2.puzzle, sizeof(s1.puzzle)) == 0;
}

// 输出状态
void printState(const State& s) {
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            cout << s.puzzle[i][j] << " ";
        }
        cout << endl;
    }
    cout << endl;
}


// 广度优先搜索算法
bool bfs(const State& start, const State& goal) {
    queue<State> pq;
    pq.push(start);

    while (!pq.empty()) {
        State current = pq.front();
        pq.pop();

        if (isEqual(current, goal)) {
            // 找到目标状态
            cout << "Found solution!" << endl;
            return true;
        }

        // 执行四个操作,将新状态加入优先队列
        State next;
        next = moveLeft(current);
        if (!isEqual(next, current)) {
            pq.push(next);
            cout << "Move Left:" << endl;
            printState(next);
        }

        next = moveRight(current);
        if (!isEqual(next, current)) {
            pq.push(next);
            cout << "Move Right:" << endl;
            printState(next);
        }

        next = moveUp(current);
        if (!isEqual(next, current)) {
            pq.push(next);
            cout << "Move Up:" << endl;
            printState(next);
        }

        next = moveDown(current);
        if (!isEqual(next, current)) {
            pq.push(next);
            cout << "Move Up:" << endl;
            printState(next);
        }
    }
    // 未找到解决方案
    cout << "No solution found." << endl;
    return false;
}

int main() {
    // 设计初始状态和目标状态
    State start = { 2, 1, 3, 8, 0, 4, 7, 6, 5 };
    State goal = { 1, 2, 3, 8, 0, 4, 7, 6, 5 };

    cout << "Initial State:" << endl;
    printState(start);

    cout << "Goal State:" << endl;
    printState(goal);

    // 调用广度优先搜索算法
    bfs(start, goal);

    return 0;
}

深度优先搜索算法部分代码(其他代码不变)

// 深度优先搜索算法
bool dfs(const State& start, const State& goal) {
    stack<State> s;
    s.push(start);

    while (!s.empty()) {
        State current = s.top();
        s.pop();

        if (isEqual(current, goal)) {
            // 找到目标状态
            cout << "Found solution!" << endl;
            return true;
        }

        // 执行四个操作,将新状态加入栈
        State next;
        next = moveLeft(current);
        // 检查是否为合法状态,避免重复搜索
        if (!isEqual(next, current)) {
            s.push(next);
        }
        next = moveRight(current);
        if (!isEqual(next, current)) {
            s.push(next);
        }
        next = moveUp(current);
        if (!isEqual(next, current)) {
            s.push(next);
        }
        next = moveDown(current);
        if (!isEqual(next, current)) {
            s.push(next);
        }
    }
}

 

A*算法

...
// 曼哈顿距离估价函数
int manhattanDistance(const State& s, const State& goal) {
    int distance = 0;
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            int value = s.puzzle[i][j];
            if (value != 0) {
                int goalRow, goalCol;
                goalRow = (value - 1) / 3;
                goalCol = (value - 1) % 3;
                distance += abs(i - goalRow) + abs(j - goalCol);
            }
        }
    }
    return distance;
}
// 输出状态
void printState(const State& s) {
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            cout << s.puzzle[i][j] << " ";
        }
        cout << "   ";
    }
    cout << "Cost: " << s.cost << " Heuristic: " << s.heuristic << endl << endl;
}

// 用于优先队列的比较函数,用于A*算法中选择最小代价的节点
struct CompareStates {
    bool operator()(const State& s1, const State& s2) {
        return (s1.cost + s1.heuristic) > (s2.cost + s2.heuristic);
    }
};

// A*搜索算法
bool aStar(const State& start, const State& goal) {
    priority_queue<State, vector<State>, CompareStates> pq;
    pq.push(start);

    while (!pq.empty()) {
        State current = pq.top();
        pq.pop();

        if (isEqual(current, goal)) {
            // 找到目标状态
            cout << "Found solution!" << endl;
            return true;
        }

        // 执行四个操作,将新状态加入优先队列
        State next;
        next = moveLeft(current);
        if (!isEqual(next, current)) {
            next.cost = current.cost + 1;
            next.heuristic = manhattanDistance(next, goal);
            pq.push(next);
        }
        next = moveRight(current);
        if (!isEqual(next, current)) {
            next.cost = current.cost + 1;
            next.heuristic = manhattanDistance(next, goal);
            pq.push(next);
        }
        next = moveUp(current);
        if (!isEqual(next, current)) {
            next.cost = current.cost + 1;
            next.heuristic = manhattanDistance(next, goal);
            pq.push(next);
        }
        next = moveDown(current);
        if (!isEqual(next, current)) {
            next.cost = current.cost + 1;
            next.heuristic = manhattanDistance(next, goal);
            pq.push(next);
        }
    }
    // 未找到解决方案
    cout << "No solution found." << endl;
    return false;
}
...

实验(二)

# 罗马利亚图存储
city_graph = [['A', 'Z', 75],
              ['A', 'T', 118],
              ['Z', 'O', 71],
              ['O', 'S', 151],
              ['A', 'S', 140],
              ['S', 'F', 99],
              ['S', 'R', 80],
              ['R', 'P', 97],
              ['R', 'C', 146],
              ['T', 'L', 111],
              ['L', 'M', 70],
              ['M', 'D', 75],
              ['D', 'C', 120],
              ['C', 'P', 138],
              ['P', 'B', 101],
              ['F', 'B', 211],
              ['B', 'G', 90],
              ['B', 'U', 85],
              ['U', 'V', 142],
              ['V', 'I', 92],
              ['I', 'N', 87],
              ['U', 'H', 98],
              ['H', 'E', 86]]
# B到其他城市的直线距离
to_B_distance = {'A': 366,
                 'B': 0,
                 'C': 160,
                 'D': 242,
                 'E': 161,
                 'F': 176,
                 'G': 77,
                 'H': 151,
                 'I': 226,
                 'L': 244,
                 'M': 241,
                 'N': 234,
                 'O': 380,
                 'P': 100,
                 'R': 163,
                 'S': 253,
                 'T': 329,
                 'U': 80,
                 'V': 199,
                 'Z': 374}
start_city = 'Z'
end_city = 'B'
# 判断某条路是否走过
def is_visited(A_city, B_city, went_road):
    for i in range(len(went_road)):
        if went_road[i][0] == A_city and went_road[i][1] == B_city:
            return 1
        if went_road[i][0] == B_city and went_road[i][1] == A_city:
            return 1
    return 0
# 根据访问结点打印结果
def print_ans(ans, distance):
    print("路径为:", end="")
    for i in range(len(ans)):
        if i != len(ans) - 1:
            print(ans[i], "->", end="")
        else:
            print(ans[i])
    print("路径长度之和为:",distance)
# 贪婪算法,每次寻找离目标城市直线距离最短的城市走
def greedy(start, end):
    print("贪婪算法:")
    went_road = []
    ans_road = [start]
    while 1:
        # 查找开始结点的所有临近城市及边
        start_near_city = []
        for item in city_graph:
            if item[0] == start:
                start_near_city.append([item[1], item[2]])
            if item[1] == start:
                start_near_city.append([item[0], item[2]])
        # 挑选到目标结点直接距离最短的城市
        direct_distance = 999
        for item in start_near_city:
            if to_B_distance[item[0]] < direct_distance and is_visited(start, item[0], went_road) == 0:
                direct_distance = to_B_distance[item[0]]
                min_distance = item[1]
                min_city = item[0]
        # 如果找到一条直线距离最短的路且没有访问过,则选择走这条路并记录走过的这条路
        if direct_distance != 999:
            went_road.append([start, min_city, min_distance])
            print(min_city, direct_distance)
            start = min_city
            ans_road.append(start)
        else:
            print("终点不可达!")
            return 0
        # 找到终点返回路径及总长度
        if start == end:
            ans_distance = 0
            for i in range(len(went_road)):
                ans_distance += went_road[i][2]
            print_ans(ans_road, ans_distance)
            return 1
# A*算法,每次寻找f=g+h最小的值走
def A_plus(start, end):
    print("A*算法:")
    went_road = []
    ans_road = [start]
    while 1:
        # 扫描图,获取与start相连的所有边
        go_to_city = []
        for item in city_graph:
            if item[0] == start:
                go_to_city.append([item[1], item[2]])
            if item[1] == start:
                go_to_city.append([item[0], item[2]])

        # 寻找fx最小的可达城市和距离,不能走回访问过的路
        hx = 0
        for j in went_road:
            hx += j[2]
        fx_distance = 999
        for item in go_to_city:
            if hx+item[1]+to_B_distance[item[0]] < fx_distance and is_visited(start, item[0], went_road) == 0:
                fx_distance = hx+item[1]+to_B_distance[item[0]]
                min_distance = item[1]
                min_city = item[0]
        # 如果找到可达的最小城市,则将其访问过的路径加入went_road
        if fx_distance != 999:
            went_road.append([start, min_city, min_distance])
            print(min_city, fx_distance)
            start = min_city
            ans_road.append(start)
        else:
            print("终点不可达!")
            return 0
        # 找到终点返回路径及总长度
        if start == end:
            ans_distance = 0
            for i in range(len(went_road)):
                ans_distance += went_road[i][2]
            print_ans(ans_road, ans_distance)
            return 1

greedy(start_city, end_city)
A_plus(start_city, end_city)

(6)实验结果讨论

实验(1)

manhattanDistance函数计算了曼哈顿距离,并且在每个状态扩展时计算了启发式估价函数。

估价函数的选择会影响算法的性能。

各搜索算法特点:

BFS:保证找到最短路径,但可能需要较多内存。

DFS:内存需求较低,但可能找到的路径不是最短的。

A*算法:结合了BFS和DFS的优点,通过选择合适的估价函数,可以找到最短路径,并在性能上进行优化。

实验(二)

思考并解答以下问题

1、你所采用的估价函数f(n) = g(n) + h(n)中,g(n)和h(n)的主要作用是什么?

g(n)表示从起始节点到当前节点n的实际代价,h(n)表示从节点n到目标节点的启发式估计代价。g(n)的主要作用是衡量已经花费的代价,h(n)则是启发式地估计剩余的代价。通过这两者的和f(n),我们可以评估当前节点n的总代价。在A*搜索算法中,选择下一个扩展的节点时,会选择f(n)最小的节点,即综合考虑实际代价和启   发式估计代价。

2、结合本实验举例说明不同启发策略对实验的效果有何影响?(可列出图表说明)

不同的启发策略对实验的效果会产生影响。在A*算法中,估价函数的选择会影响搜索的效率。例如,在罗马尼亚问题中,使用直线距离作为启发式函数可能会更快地找到解决方案,因为它提供了一种更直接的路径选择。然而,选择不同的启发式函数可能导致不同的搜索效果,有的可能更接近实际最优解,有的可能更快速但代价稍高。

3、若问题的初始状态是随机产生的,你的实验程序应该如何改进?(如图形属性的设置、图形队列存入文件等)添加代码,根据实际需要添加其他辅助函数。

  1. 将实验数据存入文件:可以将每个实验的数据(如搜索路径、代价等)存储在文件中,以便后续分析或可视化。
  2. 设置随机种子:如果使用了随机数生成器,可以设置随机种子以确保实验可重复。
  3. 添加统计信息:在程序中加入统计信息,如搜索节点的数量、路径的长度等,以便更全面地评估算法性能。

4、尝试使用一致代价(等代价)搜索, 迭代加深的深度优先搜索算法求解上述问题,并根据实验结果分析深度优先搜索,一致代价(等代价)搜索,迭代加深的深度优先搜索算法, A*搜索的时间和空间复杂度。

  1. 深度优先搜索:时间复杂度为O(b^m),其中b是分支因子,m是最大搜索深度;空间复杂度为O(bm)。
  2. 一致代价(等代价)搜索:时间复杂度和空间复杂度均为O(b^(C*/ε)),其中C*是最优解的代价,ε是最小的代价步长。
  3. 迭代加深的深度优先搜索:时间复杂度为O(b^d),其中d是最优解的深度;空间复杂度为O(bd)。
  4. A*搜索:在最坏情况下,时间复杂度为O(b^d),其中d是最优解的深度;空间复杂度为O(b^d)。

(5)指出无信息搜索策略和有信息搜索策略的不同并比较其性能。

  • 完备性:无信息搜索策略可能在某些情况下无法找到解决方案,而有信息搜索策略通常是完备的。
  • 最优性:有信息搜索策略通常更容易找到最优解,而无信息搜索策略通常只能找到可行解。
  • 时间和空间效率:有信息搜索策略通常能更快找到解决方案,但在计算和存储信息方面可能需要更多的时间和空间。
  • 领域知识要求:有信息搜索策略通常需要对问题领域有一定的了解,而无信息搜索策略对领域知识的要求较低。
  • 在实际应用中,选择无信息搜索还是有信息搜索通常取决于问题的性质和要求。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

在Centos7.9服务器上使用LVM方式挂载磁盘以及Windows磁盘性能测试与Linux磁盘性能测试命令hdparm详细

一、在Centos7.9服务器上使用LVM方式挂载磁盘 在磁盘分区挂载之前&#xff0c;先使用lsblk命令查看磁盘信息&#xff0c;未分区挂载的磁盘sdb只有disk类型没有part类型。40G的硬盘sda已经分了两个区sda1、sda2。而sdb磁盘下并没有分区信息&#xff0c;说明还没有分区。磁盘分区…

dicom基础:乳腺影像方位信息介绍

目录 一、轴位 (CC, Craniocaudal) 二、侧位 (Lateral) 三、侧斜位 (MLO, Mediolateral Oblique) 四、不同的拍摄方位的乳腺影像展示 1、RCC&#xff08;Right Craniocaudal&#xff09; 2、LCC&#xff08;Left Craniocaudal&#xff09; 3、RMLO&#xff08;Right Medio…

uniapp 报错Invalid Host header

前言 在本地使用 nginx 反向代理 uniapp 时&#xff0c;出现错误 Invalid Host header 错误原因 因项目对 hostname 进行检查&#xff0c;发现 hostname 不是预期的&#xff0c;所以&#xff0c;报错 Invalid Host header 。 解决办法 这样做是处于安全考虑。但&#xff0…

10个领先的增强现实平台【AR】

增强现实 (AR) 被描述为一种通过计算机生成的内容增强现实世界的交互式体验。 使用软件、应用程序和硬件&#xff08;例如 AR 眼镜&#xff09;&#xff0c;AR 能够将数字内容叠加到现实环境和物体上。早在 2024 年&#xff0c;许多像 Apple 这样的公司就已进入 VR/AR 市场&am…

匹配——rabin_karp是怎么滚动的?

滚动散列函数 接前面用例公式滚动last_pos第三行第二行第一行证明后话接前面 匹配——散列法里面只说前一个字符乘以128再对72057594037927931求模,答案乘以128加后一个字符再对72057594037927931求模。对应代码: hash_s = (DOMAIN * hash_s + ord(s[i])) % PRIME用例 还是…

国产数据库之Vastbase海量数据库 G100

海量数据库Vastbase是基于openGauss内核开发的企业级关系型数据库。其语法和Oracle数据库很像&#xff0c;基本是从Oracle数据库迁移到海量数据库&#xff0c;以下简单介绍入门的使用 1、建库操作 地址&#xff1a;x.x.x.x root/Qa2021 安装路径&#xff1a;/home/vastbase 创…

进程、孤儿进程、僵尸进程、fork、wait简介

进程相关概念 程序和进程 程序&#xff1a;是指编译好的二进制文件&#xff0c;在磁盘上&#xff0c;占用磁盘空间, 是一个静态的概念. 进程&#xff1a;一个启动的程序&#xff0c; 进程占用的是系统资源&#xff0c;如&#xff1a;物理内存&#xff0c;CPU&#xff0c;终端等…

【万兴科技-注册_登录安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…

【笔记】数据结构与算法

参考链接&#xff1a;数据结构(全) 参考链接&#xff1a;数据结构与算法学习笔记 一些PPT的整理&#xff0c;思路很不错&#xff0c;主要是理解角度吧&#xff0c;自己干啃书的时候结合一下会比较不错 0.总论 1.数据 注&#xff1a;图是一种数据结构&#xff01;&#xff01;…

匿名内部类的理解

这个知识点困惑我很久&#xff0c;前几天面试的时候也问到了&#xff0c;没回答出来 首先先说说使用步骤吧 1.有一个接口&#xff0c;且含有一个抽象方法&#xff08;通常情况我们不会写abstract关键字&#xff0c;冗余的&#xff09; 2.然后有一个外部类&#xff08;Anonymo…

深入探索电能消耗数据:基于机器学习的分析与洞察

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

架构的本质之 MVC 架构

前言 程序员习惯的编程方式就是三步曲。 所以&#xff0c;为了不至于让一个类撑到爆&#x1f4a5;&#xff0c;需要把黄色的对象、绿色的方法、红色的接口&#xff0c;都分配到不同的包结构下。这就是你编码人生中所接触到的第一个解耦操作。 分层框架 MVC 是一种非常常见且常…

突破挑战,创新前行 | 生信科技SOLIDWORKS 2025新品发布会·合肥站精彩回顾

2024年10月18日&#xff0c;由生信科技举办的首场SOLIDWORKS 2025新产品发布会在安徽合肥圆满落幕。现场邀请到制造业的专家学者们一同感受SOLIDWORKS 2025最新功能&#xff0c;探索制造业数字化转型之路。 合肥站活动日&#xff0c;由生信科技副总经理徐建开场。他以智造无界&…

鸿蒙HarmonyOS应用开发者(基础+高级)认证

文章目录 鸿蒙HarmonyOS应用开发者(基础高级)认证&#x1f449;1.HarmonyOS认证介绍1.1、HarmonyOS发展历程1.2、HarmonyOS NEXT 开发预览版1.3、ArkTS语言开发鸿蒙应用1.4、HarmonyOS应用开发者基础认证的核心内容1.5、HarmonyOS应用开发者高级认证的核心内容1.6、HarmonyOS应…

三菱变频器A800\F800\D700E700\CS80等系列变频器选件一览

配备了丰富的选配件&#xff0c;可以提升变频器的性能、增加功能、支持更多的安装方式等。 变频器和外围设备 选件表

精准提炼 | SOLIDWORKS 2025:工程图与钣金焊件新功能

SOLIDWORKS 每年的更新都致力于提升用户的设计效率与体验&#xff0c;SOLIDWORKS 2025 同样带来了众多改进&#xff0c;下面让我们快速了解一下在SOLIDWORKS 2025 工程图与钣金焊件方面的新功能。 工程图相关 一、表面粗糙度符号标注 新版本现在将符合更新 ISO 标准 (ISO 21…

SpringBoot核心框架之AOP详解

SpringBoot核心框架之AOP详解 一、AOP基础 1.1 AOP概述 AOP&#xff1a;Aspect Oriented Programming&#xff08;面向切面编程&#xff0c;面向方面编程&#xff09;&#xff0c;其实就是面向特定方法编程。 场景&#xff1a;项目部分功能运行较慢&#xff0c;定位执行耗时…

【万户软件-注册安全分析报告-无验证方式导致安全隐患】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 1. 暴力破解密码&#xff0c;造成用户信息泄露 2. 短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉 3. 带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造…

HBuilder X 中Vue.js基础使用4->表单输入绑定(三)

表单绑定是实现动态数据双向绑定的重要部分&#xff0c;它让开发者可以轻松地管理和响应用户输入。本文将详细介绍如何在Vue 3中利用v-model指令以及一些特定修饰符来处理不同类型的表单输入。 v-model双向数据绑定 Vue的 v-model 指令提供了双向绑定的功能&#xff0c;key在…

动态规划-回文串问题——647.回文子串

1.题目解析 题目解析&#xff1a;647.回文子串——力扣 测试用例 2.算法原理 1.状态表示 本题需要判断一段字符串是否为回文子串&#xff0c;因此最简单的方法就是保存起开始位置与结束位置&#xff0c;那么就需要一个二维的dp表来保存一段字符串是否为回文子串&#xff0c;…