人工智能原理实验一:知识的表示与推理实验

一、实验目的

本实验课程是计算机、智能、物联网等专业学生的一门专业课程,通过实验,帮助学生更好地掌握人工智能相关概念、技术、原理、应用等;通过实验提高学生编写实验报告、总结实验结果的能力;使学生对智能程序、智能算法等有比较深入的认识。本实验通过不同知识的表达与推理问题,强化学生对知识表示的了解和应用,为人工智能后续环节的课程奠定基础。

二、基本要求

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

2、准备好实验数据。

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

4、完成实验报告。

三、实验软件

使用C或C++(Visual studio平台等),或其它语言,如matlab或Python。

四、实验内容:

(一)猴子摘香蕉问题

利用一阶谓词逻辑求解猴子摘香蕉问题:房内有一个猴子,一个箱子,天花板上挂了一串香蕉,其位置如图1所示,猴子为了拿到香蕉,它必须把箱子搬到香蕉下面,然后再爬到箱子上。请定义必要的谓词,列出问题的初始化状态(即下图所示状态),目标状态(猴子拿到了香蕉,站在箱子上,箱子位于位置b)。(附加:从初始状态到目标状态的谓词演算过程。) 

1、定义描述环境状态的谓词。

AT(x,w):x在w处,个体域:x?{monkey},w?{a,b,c,box};

HOLD(x,t):x手中拿着t,个体域:t?{box,banana};

EMPTY(x):x手中是空的;

ON(t,y):t在y处,个体域:y?{b,c,ceiling};

CLEAR(y):y上是空的;

BOX(u):u是箱子,个体域:u?{box};

BANANA(v):v是香蕉,个体域:v?{banana};

2、使用谓词、连结词、量词来表示环境状态。

问题的初始状态可表示为:So:AT(monkey,a)->EMPTY(monkey)->ON(box,c)->ON(banana,ceiling)->CLEAR(b)->BOX(box)->BANANA(banana)

要达到的目标状态为:Sg:AT(monkey,box)->HOLD(monkey,banana)->ON(box,b)->CLEAR(ceiling)->CLEAR(c)->BOX(box)->BANANA(banana)

3、从初始状态到目标状态的转化, 猴子需要完成一系列操作, 定义操作类谓词表示其动作。

WALK(m,n):猴子从m走到n处,个体域:m,n?{a,b,c};

CARRY(s,r):猴子在r处拿到s,个体域:r?{c,ceiling},s?{box,banana};

CLIMB(u,b):猴子在b处爬上u;

这3个操作也可分别用条件和动作来表示。条件直接用谓词公式表示,是为完成相应操作所必须具备的条件;当条件中的事实使其均为真时,则可激活操作规则,于是可执行该规则中的动作部分。动作通过前后状态的变化表示,即通过从动作前删除或增加谓词公式来描述动作后的状态。

4、按照行动计划, 一步步进行状态替换, 直至目标状态

AT(monkey,a)?EMPTY(monkey)?ON(box,c)?ON(banana,ceiling)?CLEAR(b)?BOX(box)?

BANANA(banana)

AT(monkey,c)?EMPTY(monkey)?ON(box,c)?ON(banana,ceiling)?CLEAR(b)?BOX(box)?

BANANA(banana)

AT(monkey,c)?HOLD(monkey,box)?ON(banana,ceiling)?CLEAR(b)?CLEAR(c)?BOX(box)?

BANANA(banana)

AT(monkey,b)?HOLD(monkey,box)?ON(banana,ceiling)?CLEAR(b)?CLEAR(c)?BOX(box)?

BANANA(banana)

AT(monkey,box)?EMPTY(monkey)?ON(box,b)?ON(banana,ceiling)?CLEAR(c)?BOX(box)?

BANANA(banana)

AT(monkey,box)?HOLD(monkey,banana)?ON(box,b)?CLEAR(ceiling)?CLEAR(c)?BOX(box)?

BANANA(banana)(目标得解)

猴子行动的规则序列是:WALK(a,c)→CARRY(c,box)→WALK(c,b)→CLIMB(box,b)→

CARRY(banana,ceiling)

5、参考代码:

#include <stdio.h>
struct State
{
	int monkey; /*-1:Monkey at A;0: Monkey at B;1:Monkey at C;*/
    int box; /*-1:box at A;0:box at B;1:box at C;*/
    int banana; /*Banana at B,Banana=0*/
    int monbox; /*-1: monkey on the box;1: monkey  the box;*/
};
struct State States [150];
char* routesave[150];
/*function monkeygoto,it makes the monkey goto the other place*/
void monkeygoto(int b,int i)
{  
	int a;
	a=b;
	if (a==-1)
	{
		routesave[i]="Monkey go to A";
		States[i+1]=States[i];
		States[i+1].monkey=-1;
	}
	else if(a==0)
	{
		routesave[i]="Monkey go to B";
		States[i+1]=States[i];
		States[i+1].monkey=0;
	}
	else if(a==1)
	{
		routesave[i]="Monkey go to C";
		States[i+1]=States[i];
		States[i+1].monkey=1;
	}
	else
    {
		printf("parameter is wrong");
	}
}
/*end function monkeyygoto*/
/*function movebox,the monkey move the box to the other place*/
void movebox(int a,int i)
{  
	int B;
	B=a;
	if(B==-1)
	{
		routesave[i]="monkey move box to A";
		States[i+1]=States[i];
		States[i+1].monkey=-1;
		States[i+1].box=-1;
	}
	else if(B==0)
	{
		routesave[i] = "monkey move box to B";
		States[i+1]=States[i];
		States[i+1].monkey=0;
		States[i+1].box=0;
	}
	else if(B==1)
	{
		routesave[i] = "monkey move box to C";
		States[i+1]=States[i];
		States[i+1].monkey=1;
		States[i+1].box=1;
	}
	else
	{
		printf("parameter is wrong");
	}
}
/*end function movebox*/
/*function climbonto,the monkey climb onto the box*/
void climbonto(int i)
{
	routesave[i]="Monkey climb onto the box";
	States[i+1]=States[i];
	States[i+1].monbox=1;
}
/*function climbdown,monkey climb down from the box*/
void climbdown(int i)
{  
	routesave[i]="Monkey climb down from the box";
	States[i+1]=States[i];
	States[i+1].monbox=-1;
}
/*function reach,if the monkey,box,and banana are at the same place,the monkey reach banana*/
void reach(int i)
{   
	routesave[i]="Monkey reach the banana";
}
/*output the solution to the problem*/
void showSolution(int i)
{
    int c;
    printf ("%s \n", "Result to problem:");
    for(c=0; c<i+1; c++)
    {
		printf ("Step %d : %s \n",c+1,routesave[c]);
    }
    printf("\n");
}
/*perform next step*/
void nextStep(int i)
{
	int c;
    int j;
    if(i>=150)
    {
		printf("%s  \n", "steplength reached 150,have problem ");
        return;
    }
	for (c=0; c<i; c++) /*if the current state is same to previous,retrospect*/
    {
		if(States[c].monkey==States[i].monkey&&States[c].box==States[i].box&&States[c].banana==States[i].banana&&States[c].monbox==States[i].monbox)
        {
			return;
        }
    }
    if(States[i].monbox==1&&States[i].monkey==0&&States[i].banana==0&&States[i].box==0)
    {
		showSolution(i);
		printf("Press any key to continue \n");
		getchar();/*to save screen for user,press any key to continue*/
		return;
	}  
	j=i+1;    
	if(States[i].monkey==0)
	{ 
		if(States[i].box==0)
		{
			if(States[i].monbox==-1)
			{
				climbonto(i);
				reach(i+1);
				nextStep(j);
				/*monkeygoto(-1,i);
				nextStep(j);
				monkeygoto(0,i);
				nextStep(j);
				movebox(-1,i);
				nextStep(j);
				movebox(0,i);
				nextStep(j);*/
			}
			else
			{
				reach(i+1);
				nextStep(j);
				/*climbdown(i);
				nextStep(j);*/
			}
		}
		else if(States[i].box==1)
		{
			/*monkeygoto(-1,i);
			nextStep(j);*/
			monkeygoto(1,i);
			nextStep(j);
			movebox(0,i);
			nextStep(j);
			climbonto(i);
			reach(i+1);
			nextStep(j);
		}
		else /*box==-1*/
		{
			monkeygoto(-1,i);
			nextStep(j);
			movebox(0,i);
			nextStep(j);
			climbonto(i);
			reach(i+1);
			nextStep(j);
		}
    }
	/*end if*/
	if(States[i].monkey==-1)
    { 
		if(States[i].box==-1)
		{
			if(States[i].monbox==-1)
			{ 
				movebox(0,i);
				nextStep(j);
				climbonto(i);
				reach(i+1);
				nextStep(j);
			}
			else
			{
				climbdown(i);
				nextStep(j);
				movebox(0,i);
				nextStep(j);
				climbonto(i);
				reach(i+1);
				nextStep(j);
			}
		}
		else if(States[i].box==0)
		{ 
			monkeygoto(0,i);
			nextStep(j);
			climbonto(i);
			reach(i+1);
			nextStep(j);
		}
		else
		{
			monkeygoto(1,i);
			nextStep(j);
			movebox(0,i);
			nextStep(j);
			climbonto(i);
			reach(i+1);
			nextStep(j);
		}
	}
	/*end if*/
	if(States[i].monkey==1)
    {	
		if (States[i].box==1)
		{
			if(States[i].monbox==-1)
			{     
				movebox(0,i);
				nextStep(j);
				climbonto(i);
				reach(i+1);
				nextStep(j);
			}
			else
			{
				climbdown(i);
				nextStep(j);
				movebox(0,i);
				nextStep(j);
				climbonto(i);
				reach(i+1);
				nextStep(j);          
			}
		}
		else if(States[i].box==-1)
		{        
			monkeygoto(-1,i);
			nextStep(j);
			movebox(0,i);
			nextStep(j);
 			movebox(0,i);
			nextStep(j);
			climbonto(i);
			reach(i+1);
			nextStep(j);
		}
		else
		{
			monkeygoto(0,i);
			nextStep(j);
			movebox(0,i);
			nextStep(j);
			climbonto(i);
			reach(i+1);
			nextStep(j);
		}
    }
	/*end if*/
}/*end nextStep*/
int main()
{
    States[0].monkey=-1;
    States[0].box=1;
    States[0].banana=0;
    States[0].monbox=-1;
    nextStep(0);
}

(二)传教士(牧师)与野人问题

问题描述:

有n个牧师和n个野人准备渡河,但只有一条能容纳c个人的小船,为了防止野人侵犯牧师,要求无论在何处,牧师的人数不得少于野人的人数(除非牧师人数为0),且假定野人与牧师都会划船,试设计一个算法,确定他们能否渡过河去,若能,则给出小船来回次数最少的最佳方案。

实验步骤:

输入:牧师人数(即野人人数):n;小船一次最多载人量:c。  

输出:若问题无解,则显示Failed,否则,显示Successed输出所有可行方案,并标注哪一组是最佳方案。用三元组(X1, X2, X3)表示渡河过程中的状态。并用箭头连接相邻状态以表示迁移过程:初始状态->中间状态->目标状态。   

例:当输入n=2,c=2时,输出:221->200->211->010->021->000;  

其中:X1表示起始岸上的牧师人数;X2表示起始岸上的野人人数;X3表示小船现在位置(1表示起始岸,0表示目的岸)。

要求:写出算法的设计思想和源程序,并有用户界面实现人机交互(控制台或者窗口都可以),进行输入和输出结果,如:

Please input n: 2         Please input c: 2

Optimal Procedure: 221->200->211->010->021->000

Successed or Failed?: Successed     

五、学生实验报告要求

(1)对于猴子摘香蕉问题根据自己编写代码或者参考代码,用不同的初始状态测试代码,记录每种初始状态下的输出结果,并对每个结果进行解释。

(2)完善猴子摘香蕉问题参考代码,参考代码中有什么问题?应该如何修改会更好。

问题:

1. 数组索引和函数调用:

   使用数组索引i访问和更新状态。确保数组索引在范围内,以避免潜在的内存问题。

   考虑将状态数组封装在结构体内部或将其作为参数传递给函数,而不是使用全局数组。

2. 字符串赋值:

   避免直接将字符串赋值给 routesave[i],例如 routesave[i] = "Monkey go to A";,使用strcpy或类似的函数进行字符串赋值,以避免潜在的问题。

3. 未使用的变量:

   movebox函数中声明了变量int B;但未使用。移除它以避免混淆。

4. 递归函数:

   nextStep 函数是递归的,它一直调用自身。这可能会导致大量步骤时发生堆栈溢出。考虑使用迭代方法,或者根据需要增加堆栈大小。

5. 内存管理:

   代码使用一个固定大小的数组 (States[150]) 存储状态。如果状态数量不能事先确定,考虑使用动态内存分配或其他数据结构。

(3)传教士(牧师)与野人问题,写出状态表示的数据结构,还有每种解的状态迁移图示。

struct State {
    int m;//传教士
    int c;//野人
    int dep;//已划船次数
    int boat;//左岸是否有船
    bool friend operator <(const struct State& a, const struct State& b)//为实现自定义类型的set提供排序规则
    {
        return a.dep < b.dep;//升序排序
    }
};

例:n=2,c=2时:

1.(2,2,1) -> (2,0,0) -> (2,1,1) -> (0,1,0) -> (0,2,1) -> (0,0,0)

2.(2,2,1) -> (2,0,0) -> (2,1,1) -> (0,1,0) -> (1,1,1) -> (0,0,0)

3.(2,2,1) -> (1,1,0) -> (2,1,1) -> (0,1,0) -> (0,2,1) -> (0,0,0)

4.(2,2,1) -> (1,1,0) -> (2,1,1) -> (0,1,0) -> (1,1,1) -> (0,0,0)

(4)写出传教士(牧师)与野人问题的程序清单(语言不限)

#include<iostream>
#include<set>
#include<vector>
using namespace std;

int n, c;//传教士的人数及船的载客量
int min_deep = INT_MAX;//船的最小来回次数
int path = 0;//可达路径的数量

struct State {
    int m;//传教士
    int c;//野人
    int dep;//已划船次数
    int boat;//左岸是否有船
    bool friend operator <(const struct State& a, const struct State& b)//为实现自定义类型的set提供排序规则
    {
        return a.dep < b.dep;//升序排序
    }
};
set<State> Set;//自定义类型State实现set
vector<vector<State>> res;//保存所有路径

//判断状态是否已经在当前路径中,避免重复加入
bool isExist(State next)
{
    for (auto it = Set.begin(); it != Set.end(); it++)
        if (it->m == next.m && it->c == next.c && it->boat == next.boat)
            return true;
    return false;
}
//输出路径
void output()
{
    for (int i = 0; i < res.size(); i++)
    {
        if (res[i].size() == min_deep + 1)//判断是否为最优路径
            cout << "optimal" << endl;
        cout << "Solution" << i + 1 << endl;
        for (int j = 0; j < res[i].size(); j++)//依次输出路径上的各个状态
            cout << "(" << res[i][j].m << "," << res[i][j].c << "," << res[i][j].boat << ")" << endl;
        cout << endl;
    }
}
//用深度优先进行搜索
void dfs(State s)
{
    Set.insert(s);//加入当前路径的集合中(已按状态的先后顺序排序)
    if (s.m == 0 && s.c == 0)//目标状态
    {
        if (s.dep < min_deep)//记录最短路径的划船次数
            min_deep = s.dep;
        path++;
        vector<State> v(Set.begin(), Set.end());
        res.push_back(v);//保存该路径
        Set.erase(--Set.end());//已达终点,进行回退
        return;
    }
    if (s.boat == 1)//左岸
    {
        for (int i = c; i >= 1; i--)//船载i从左往右划
        {
            if (i > s.m + s.c)//i多于左岸的总人数
                continue;
            for (int j = i; j >= 0; j--)//船上有j个野人
            {
                if (j > s.c || i - j > s.m)//多于左岸传教士、野人的实际人数
                    continue;
                if (j != i && j > i - j)//船上传教士的人数少于野人的人数
                    continue;
                if (s.m - (i - j) != 0 && s.m - (i - j) != n && s.m - (i - j) != s.c - j)//左岸剩下的传教士与野人的人数不相等
                    continue;
                State next;
                next.boat = 0;
                next.m = s.m - (i - j);
                next.c = s.c - j;
                next.dep = s.dep + 1;
                if (!isExist(next))//判断当前路径是否存在该状态
                    dfs(next);
            }
        }
    }
    else//右岸
    {
        for (int i = c; i >= 1; i--)//船载i个人从右往左划
        {
            if (i > (n - s.m) + (n - s.c))//i多于右岸的总人数
                continue;
            for (int j = i; j >= 0; j--)//船上有j个野人
            {
                if (j > n - s.c || i - j > n - s.m)//多于右岸传教士、野人的实际人数
                    continue;
                if (j != i && j > i - j)//船上野人的数量大于传教士的数量
                    continue;
                if (n - s.m - (i - j) != 0 && n - s.m - (i - j) != n && n - s.m - (i - j) != n - s.c - j)//右岸剩下的传教士人数与野人不相等
                    continue;
                State next;
                next.boat = 1;
                next.m = s.m + (i - j);
                next.c = s.c + j;
                next.dep = s.dep + 1;
                if (!isExist(next))//判断当前路径是否存在该状态
                    dfs(next);
            }
        }
    }
    Set.erase(--Set.end());//无路可走,进行回退
}

int main()
{
    cout << "请输入传教士(野人)人数:";
    cin >> n;
    cout << endl;
    cout << "请输入船的载人量:";
    cin >> c;
    State start;//初始状态
    start.m = start.c = n;
    start.boat = 1;
    start.dep = 0;
    dfs(start);
    cout << "Successed or Failed?:";
    if (path == 0)
        cout << "failed" << endl;
    else
    {
        cout << "Successed" << endl;
        output();
        cout << "共有" << path << "条路径。" << endl;
        cout << "min_deep=" << min_deep << endl;
    }
}

(5)实验结果讨论。

这是n=2,c=2的情况,共有四种情况的最短路径,最短路径为5

这是n=3,c=2的情况,共有四种情况的最短路径,最短路径为11

3 汉诺塔问题

汉诺塔问题来自一个古老的传说:在世界刚被创建的时候有一座钻石宝塔(塔A),其上有64个金碟。所有碟子按从大到小的次序从塔底堆放至塔顶。紧挨着这座塔有另外两个钻石宝塔(塔B和塔C)。从世界创始之日起,婆罗门的牧师们就一直在试图把塔A上的碟子移动到塔C上去,其间借助于塔B的帮助。每次只能移动一个碟子,任何时候都不能把一个碟子放在比它小的碟子上面。当牧师们完成任务时,世界末日也就到了。

  采用问题归约法把汉诺塔问题分成以下三个步骤实现:

  1. 将塔A上的n-1个碟子借助塔C先移到塔B上
  2. 把塔A上剩下的一个碟子移到塔C上
  3. 把n-1个碟子从塔B借助于塔A移到塔C上

实验要求: 

  1. 让盘子数从2 开始到7进行实验,记录程序运行时间和递归调用次数。

2.画出盘子数n和运行时间t 、递归调用次数m的关系图,并进行分析

分析:

运行时间 vs 盘子数(n): 通常来说,汉诺塔问题的解决时间呈指数增长。图表中应该看到一个指数曲线,显示随着盘子数的增加,解决问题所需的时间迅速增加。但是运行时间都太短了,看不出明显趋势。

递归调用次数 vs 盘子数(n): 递归调用次数也是指数级增长的,因为每增加一个盘子,递归调用次数就翻倍。这与汉诺塔问题的递归性质相一致。

在解决类似指数级增长问题时,递归算法可能会面临的性能挑战。

实验代码:

import time

def hanoi(n, source, target, auxiliary):
    global recursive_calls
    if n > 0:
        recursive_calls += 1
        hanoi(n - 1, source, auxiliary, target)
        # 移动盘子
        # print(f"Move disk {n} from {source} to {target}")
        hanoi(n - 1, auxiliary, target, source)

def run_experiment(n):
    global recursive_calls
    recursive_calls = 0
    start_time = time.time()
    hanoi(n, 'A', 'C', 'B')
    end_time = time.time()
    execution_time = end_time - start_time
    return execution_time, recursive_calls

# 实验
results = []
for i in range(2, 8):
    time_taken, calls_made = run_experiment(i)
    results.append((i, time_taken, calls_made))

# 打印结果
print("n\tTime(s)\tRecursive Calls")
for result in results:
    print(f"{result[0]}\t{result[1]:.6f}\t{result[2]}")

import matplotlib.pyplot as plt

def plot_results(results):
    n_values = [result[0] for result in results]
    time_values = [result[1] for result in results]
    calls_values = [result[2] for result in results]

    # Plotting time vs n
    plt.figure(figsize=(10, 5))
    plt.subplot(1, 2, 1)
    plt.plot(n_values, time_values, marker='o')
    plt.title('Time vs Number of Disks')
    plt.xlabel('Number of Disks (n)')
    plt.ylabel('Time (s)')

    # Plotting recursive calls vs n
    plt.subplot(1, 2, 2)
    plt.plot(n_values, calls_values, marker='o', color='r')
    plt.title('Recursive Calls vs Number of Disks')
    plt.xlabel('Number of Disks (n)')
    plt.ylabel('Recursive Calls')

    plt.tight_layout()
    plt.show()

# 实验
results = []
for i in range(2, 8):
    time_taken, calls_made = run_experiment(i)
    results.append((i, time_taken, calls_made))

# 绘制图表
plot_results(results)

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

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

相关文章

虚拟机 Email 恢复专用工具:Virtual Machine Email Recovery

天津鸿萌科贸发展有限公司从事数据安全服务二十余年&#xff0c;致力于为各领域客户提供专业的数据恢复、数据备份解决方案与服务&#xff0c;并针对企业面临的数据安全风险&#xff0c;提供专业的相关数据安全培训。 天津鸿萌科贸发展有限公司是 SysTools 系列数据恢复、取证及…

HTML 基础标签——表单标签<form>

文章目录 1. `<form>` 标签:定义表单容器2. `<input>` 标签:多用途输入控件3. `<textarea>` 标签:多行文本输入框4. `<select>` 标签:下拉选择框5. `<option>` 标签:下拉菜单选项6. `<button>` 标签:按钮元素7. `<label>` 标签…

使用Jupyter Notebook进行数据科学项目

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 使用Jupyter Notebook进行数据科学项目 Jupyter Notebook 简介 安装 Jupyter Notebook 创建和管理 Notebook 编写和运行代码 示例…

详解RabbitMQ三种队列类型

RabbitMQ 是一个强大的消息队列系统&#xff0c;它提供了多种队列类型以满足不同的使用需求。本文将探讨三种主要队列类型&#xff1a;经典队列、仲裁队列和流式队列&#xff0c;并讨论它们的区别和选型建议。 经典队列&#xff08;Classic Queues&#xff09; 简介&#xff…

【AD】2-1 元件符号的绘制创建实例-电阻容/CHIP类器件

1.新建工程后&#xff0c;双击原理图库&#xff0c;点击Panels后&#xff0c;选择SCH Library&#xff0c;双击元器件可在右侧进行更改名称 2.点击视图&#xff0c;栅格&#xff0c;设置捕捉栅格为100mil 3.点击放置管脚&#xff0c;可按空格键进行旋转&#xff0c;按TAB键可以…

JDBC2(防止sql注入,数据库连接池)

防止SQL注入 sql注入&#xff1a;利用sql语句的语法特点&#xff0c;应用层输入特殊格式&#xff0c;让原有的sql语句失效 创建表结构 并加入数据 create table login(lid int primary key auto_increment,lname varchar(20),lpwd varchar(20),lsex varchar(2),laddr varcha…

基于SSM+微信小程序的订餐管理系统(点餐2)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1、项目介绍 基于SSM微信小程序的订餐管理系统实现了管理员和用户。管理端实现了 首页、个人中心、用户管理、菜品分类管理、菜品信息管理、订单信息管理、配送信息管理、菜品评价管理、订单投诉管理、…

MRCTF2020:你传你ma呢

文件上传题先判断黑白名单过滤&#xff0c;先传个最简单的木马 这里上传不了php文件&#xff0c;猜测可能是对php文件进行了过滤&#xff0c;将文件改为任意后缀这里改为.abc 还是上传不成功&#xff0c;猜测可能对MIME也做了过滤&#xff0c;将Content-Type更改为image/jpeg再…

设计模式09-行为型模式2(状态模式/策略模式/Java)

5.4 状态模式 5.4.1 状态模式的定义 1.模式动机&#xff1a;有些对象具有多种状态&#xff0c;这些状态在某些情况下能够相互转换&#xff0c;对象在不同的状态下将具有不同的行为&#xff0c;将拥有状态的对象中和状态的行为分离。 2.模式定义&#xff1a;允许一个对象在其…

tauri中shell的特殊字符

tauri中shell的特殊字符 官网例子&#xff1a;https://tauri.app/plugin/shell/ 中的入参是 \S 入参&#xff0c;但如果入参存在空格等特殊字符串&#xff0c;将无法传入 "permissions": [{"identifier": "shell:allow-execute","allow&qu…

电子电气架构 --- Trace 32(劳特巴赫)多核系统的调试

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所有人的看法和评价都是暂时的,只有自己的经历是伴随一生的,几乎所有的担忧和畏惧,都是来源于自己的想象,只有你真的去做了,才会发现有多快乐。…

使用Web Workers实现JavaScript的多线程编程

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 使用Web Workers实现JavaScript的多线程编程 引言 Web Workers 简介 创建和使用 Worker 通信机制 主线程向 Worker 发送消息 Wor…

【uni-app】创建自定义模板

1. 步骤 打开自定义模板文件夹 在此文件夹下创建模板文件&#xff08;注意后缀名&#xff09; 重新点击“新建页面” 即可看到新建的模板 2. 注意事项 创建的模板必须文件类型对应&#xff08;vue模板就创建*.vue文件, uvue模板就创建*.uvue文件&#xff09;

【云原生】Docker搭建开源翻译组件Deepl使用详解

目录 一、前言 二、微服务项目使用翻译组件的场景 2.1 多语言用户界面 2.2 业务逻辑中的翻译需求 2.3 满足实时通信的要求 2.4 内容管理系统 2.5 个性化推荐系统 2.6 日志和监控 三、开源类翻译组件解决方案 3.1 国内翻译组件方案汇总 3.1.1 百度翻译 3.1.2 腾讯翻…

Hms?: 1渗透测试

靶机&#xff1a;Hms?: 1 Hms?: 1 ~ VulnHub 攻击机&#xff1a;kail linux 2024 主机扫描阶段发现不了靶机&#xff0c;所以需要按DriftingBlues2一样手动配置网卡 1,将两台虚拟机网络连接都改为NAT模式&#xff0c;并查看靶机的MAC地址 2&#xff0c;攻击机上做主机扫描发现…

linux-环境变量

环境变量是系统提供的一组 name value 的变量&#xff0c;不同的变量有不同的用途&#xff0c;通常都具有全局属性 env 查看环境变量 PATH PATH是一个保存着系统指令路径的一个环境变量&#xff0c;系统提供的指令不需要路径&#xff0c;直接就可以使用就是因为指令的路径…

基于Spring Boot的私房菜定制上门服务系统的设计与实现

摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统私房菜定制上门服务系统信息管理难度大&#xff0c;容错率…

qt QMenuBar详解

1、概述 QMenuBar是Qt框架中用于创建菜单栏的类&#xff0c;它继承自QWidget。QMenuBar通常位于QMainWindow对象的标题栏下方&#xff0c;用于组织和管理多个QMenu&#xff08;菜单&#xff09;和QAction&#xff08;动作&#xff09;。菜单栏提供了一个水平排列的容器&#x…

转载:【lwip】03-内存管理 - 李柱明 - 博客园

目录 前言3. 内存管理 3.1 内存分配策略 3.1.1 固定大小的内存块3.1.2 可变大小分配3.2 动态内存池&#xff08;pool&#xff09; 3.2.1 介绍3.2.2 内存池的预处理3.2.3 内存池的初始化3.2.4 内存分配3.2.5 内存释放3.2.6 内存池源码定义简要分析 定义内存池资源源码分析保存各…

「Mac畅玩鸿蒙与硬件25」UI互动应用篇2 - 计时器应用实现

本篇将带领你实现一个实用的计时器应用&#xff0c;用户可以启动、暂停或重置计时器。该项目将涉及时间控制、状态管理以及按钮交互&#xff0c;是掌握鸿蒙应用开发的重要步骤。 关键词 UI互动应用时间控制状态管理用户交互 一、功能说明 在这个计时器应用中&#xff0c;用户…