第一篇:人工智能_实验报告
实验一:知识表示方法
一、实验目的
状态空间表示法是人工智能领域最基本的知识表示方法之一,也是进一步学习状态空间搜索策略的基础,本实验通过牧师与野人渡河的问题,强化学生对知识表示的了解和应用,为人工智能后续环节的课程奠定基础。
二、问题描述
有n个牧师和n个野人准备渡河,但只有一条能容纳c个人的小船,为了防止野人侵犯牧师,要求无论在何处,牧师的人数不得少于野人的人数(除非牧师人数为0),且假定野人与牧师都会划船,试设计一个算法,确定他们能否渡过河去,若能,则给出小船来回次数最少的最佳方案。
三、基本要求
输入:牧师人数(即野人人数):n;小船一次最多载人量:c。
输出:若问题无解,则显示Failed,否则,显示Successed输出一组最佳方案。用三元组(X1, X2, X3)表示渡河过程中的状态。并用箭头连接相邻状态以表示迁移过程:初始状态->中间状态->目标状态。
例:当输入n=2,c=2时,输出:221->110->211->010->021->000 其中:X1表示起始岸上的牧师人数;X2表示起始岸上的野人人数;X3表示小船现在位置(1表示起始岸,0表示目的岸)。
要求:写出算法的设计思想和源程序,并以图形用户界面实现人机交互,进行输入和输出结果,如:
Please input n: 2
Please input c: 2 Successed or Failed?: Successed Optimal Procedure: 221->110->211->010->021->000
四、实验组织运行要求
本实验采用集中授课形式,每个同学独立完成上述实验要求。
五、实验条件
每人一台计算机独立完成实验。
六、实验代码
Main.cpp #include
//主函数 void main(){
} system(“pause”);RiverCrossing riverCrossing(n, c);riverCrossing.solve();int n, c;cout<<“Please input n: ”;cin>>n;cout<<“Please input c: ”;cin>>c;RiverCrossing::ShowInfo();
RiverCrossing.h #pragma once #include
//船 class Boat { public:
};
//河岸状态 class State Boat(int pastor, int savage);static int c;int pastor;//牧师 int savage;//野人
{ public:
};
//过河问题
class RiverCrossing { private:
};bool move(State *nowState, Boat *boat);//进行一次决策
State* findInList(std::list
State operator +(Boat &boat);State operatorboat.pastor, iSavage1);ret.pPrevious = this;return ret;State ret(iPastor + boat.pastor, iSavage + boat.savage, iBoatAtSide + 1);ret.pPrevious = this;return ret;
} openList.push_back(new State(State::n, State::n, 1));while(!openList.empty()){
} print(NULL);return false;//获取一个状态为当前状态
State *nowState = openList.front();openList.pop_front();closeList.push_back(nowState);//从当前状态开始决策
if(nowState->iBoatAtSide == 1){//船在此岸
} //过河的人越多越好,且野人优先
int count = nowState->getTotalCount();count =(Boat::c >= count ? count : Boat::c);for(int capticy = count;capticy >= 1;--capticy){
} //把船开回来的人要最少,且牧师优先
for(int capticy = 1;capticy <= Boat::c;++capticy){
} for(int i = 0;i <= capticy;++i){
} Boat boat(capticyi);if(move(nowState, &boat))
return true;} else if(nowState->iBoatAtSide == 0){//船在彼岸
//实施一步决策,将得到的新状态添加到列表,返回是否达到目标状态 bool RiverCrossing::move(State *nowState, Boat *boat){
//获得下一个状态 State *destState;if(nowState->iBoatAtSide == 1){
} destState = new State(*nowState1< iSavage<<“,”< iBoatAtSide;if(st.size()> 0)cout<<“-> ”;cout< cout<<“==”< 七、实验结果 实验二:九宫重排 一、实验目的 A*算法是人工智能领域最重要的启发式搜索算法之一,本实验通过九宫重排问题,强化学生对A*算法的理解与应用,为人工智能后续环节的课程奠定基础。 二、问题描述 给定九宫格的初始状态,要求在有限步的操作内,使其转化为目标状态,且所得到的解是代价最小解(即移动的步数最少)。如: 三、基本要求 输入:九宫格的初始状态和目标状态 输出:重排的过程,即途径的状态 四、实验组织运行要求 本实验采用集中授课形式,每个同学独立完成上述实验要求。 五、实验条件 每人一台计算机独立完成实验。 六、实验代码 Main.cpp #include //主函数 void main(){ NineGrid::ShowInfo(); } string start, end;cout<<“Please input the initial state:(ex:134706582)”< NineGrid.h #pragma once #include #define SPACE '0' #define AT(s, x, y)(s)[(x)* 3 +(y)] enum Move { }; //九宫格状态 class State { public: int moves;//到此状态的移动次数 int value;//价值 State *pPrevious;//前一个状态 State(string &grid, State *pPrevious = NULL);int getReversedCount();//获取逆序数 void evaluate();//评价函数 bool check(Move move);//检查是否可以移动 string grid;//用字符串保存当前棋盘状态 int x, y;//空格所在位置 static State *pEndState;//指向目标状态,用于评价h的值 UP = 0, DOWN = 1, LEFT = 2, RIGHT = 3 };State takeMove(Move move);//实施移动,生成子状态 //重载==运算符,判断两个状态是否相等 inline bool operator ==(State &state){ return grid == state.grid;} //九宫重排问题 class NineGrid { private: }; NineGrid.cpp #include “NineGrid.h” #include State* State::pEndState = NULL; /*=======================Methods for class “State”=======================*/ //构造函数 State::State(string &grid, State *pPrevious){ this->grid = grid;NineGrid(string &start, string &dest);bool solve();//求解问题 //用于排序 static bool greater_than(const State *state1, const State *state2);static void ShowInfo();//显示信息 bool compareReversed();//比较逆序数奇偶性是否相同 bool takeMove(State *nowState, Move move);//进行一次决策 State* findInList(vector public: } this->pPrevious = pPrevious;if(this->pPrevious)this->moves = pPrevious->moves + 1;this->moves = 0;else this->value = 0;evaluate();for(int i = 0;i < 3;++i){ } for(int j = 0;j < 3;++j){ } if(AT(grid, i, j)== SPACE){ } x = i;y = j;return;bool State::check(Move move){ } State State::takeMove(Move move){ switch(move){ case UP: } return true;if(x1 < 0)return false;break;if(y + 1 >= 3)return false;break;case DOWN: case LEFT: case RIGHT: } int destX, destY;switch(move){ case UP: } string tGrid = grid;char t = AT(tGrid, destX, destY);AT(tGrid, destX, destY)= AT(tGrid, x, y);AT(tGrid, x, y)= t;return State(tGrid, this);destX = x1;break;destX = x;destY = y + 1;break;case DOWN: case LEFT: case RIGHT: void State::evaluate(){ for(int ii = 0;ii < 3;++ii){ for(int jj = 0;jj < 3;++jj){ if(AT(grid, i, j)== AT(pEndState->grid, ii, jj)){ h += abs(ijj);int g = moves, h = 0;for(int i = 0;i < 3;++i){ for(int j = 0;j < 3;++j){ //if(AT(grid, i, j)!= AT(pEndState->grid, i, j))// ++h; if(AT(grid, i, j)== SPACE)continue;if(!pEndState)return; } } } } } } this->value = g + h;//求该状态的逆序数 //逆序数定义为: // 不计空格,将棋盘按顺序排列,// 对于grid[i],存在jgrid[i],即为逆序。// 所有棋子的逆序总数为逆序数。int State::getReversedCount(){ } /*=====================Methods for class “NineGrid”=====================*/ //显示信息 void NineGrid::ShowInfo(){ } //构造函数 NineGrid::NineGrid(string &start, string &dest): startState(start), endState(dest)cout<<“************************************************”< } return count; } if(grid[i] > grid[j])++count;int count = 0;for(int i = 0;i < 9;++i){ if(grid[i] == SPACE) continue;if(grid[j] == SPACE)continue;for(int j = 0;j < i;++j){ { } //当初始状态和目标状态的逆序数的奇偶性相同时,问题才有解 bool NineGrid::compareReversed(){ 2;} //解决问题 bool NineGrid::solve(){ } //实施一步决策,将得到的新状态添加到列表,返回是否达到目标状态 } print(NULL);return false; } //从当前状态开始决策 for(int i = 0;i < 4;++i){ } Move move =(Move)i;if(nowState->check(move)){ } if(takeMove(nowState, move)) return true; openList.push_back(new State(startState));while(!openList.empty()){ //获取一个状态为当前状态 State *nowState = openList.back();openList.pop_back();closeList.push_back(nowState);cout<<“==”< cout<<“初始状态和目标状态的逆序数的奇偶性不同,问题无解!”< bool NineGrid::takeMove(State *nowState, Move move){ } //检查给定状态是否存在于列表中 State* NineGrid::findInList(vector } //根据达到的目标状态,回溯打印出求解过程 void NineGrid::print(State *endState){ cout<<“Search successed!”< addSymptom(pDisease, strInput);} else { ioFile.close();return true;//添加一个疾病,返回此疾病信息的指针 Disease* Expert::addDisease(const string &name){ } //添加疾病的症状 void Expert::addSymptom(Disease *disease,const string &symptom){ } //诊断函数 void Expert::diagnosis(){ cout<<“【症状询问】”< vector vector for(vector bool remove = false;//是否从findList列表中排除本疾病 for(unsigned int j = 0;j <(*ite)->symptomList.size();++j){ Disease *pDisease = *ite;if(find(symptomNotHave.begin(), symptomNotHave.end(),//在symptomNotHave列表中找到此症状,直接排除 remove = true;break;findList.end();){ if(symptomInput == “不确定”){ } //添加所有疾病到findList列表中 for(unsigned int i = 0;i < m_DiseaseList.size();++i){ } //添加有此症状的疾病到findList列表中 for(unsigned int i = 0;i < m_DiseaseList.size();++i){ } //添加输入的症状到symptomHave列表中 symptomHave.push_back(symptomInput);Disease *pDisease = &m_DiseaseList[i];for(unsigned int j = 0;j < pDisease->symptomList.size();++j){ } if(symptomInput == pDisease->symptomList[j]){ } findList.push_back(pDisease);findList.push_back(&m_DiseaseList[i]);} else { pDisease->symptomList[j])!= symptomNotHave.end()){ } else if(find(symptomHave.begin(), symptomHave.end(),//在symptomHave,symptomNotHave列表中不存在这个症状,则询问 if(optionSelect(“->是否有症状”“ + pDisease->symptomList[j] + } //询问得知有此症状,添加症状到symptomHave列表中 symptomHave.push_back(pDisease->symptomList[j]);//询问得知没有此症状,添加症状到symptomNotHave列表中,并排除symptomNotHave.push_back(pDisease->symptomList[j]);remove = true;break;pDisease->symptomList[j])== symptomHave.end()){ ”“?n(y/n): ”)){ } else { 此疾病 } } } } if(remove){ } //需要排除此疾病 ite = findList.erase(ite);//迭代器后移 ++ite;} else { cout< } cout< for(unsigned int i = 0;i < findList.size();++i){ } cout< bool Expert::optionSelect(const string &question){ cout< switch(option){ case 'Y': case 'y': return true;case 'N': case 'n': } return false; } return false; Disease.txt [疾病1] 症状A 症状B 症状C 症状D [疾病2] 症状A 症状B 症状C [疾病3] 症状A 症状B 症状D 症状E [疾病4] 症状A 症状C 症状D [疾病5] 症状B 症状C 症状D 症状E [疾病6] 症状A 症状B [疾病7] 症状A 症状C 症状E [疾病8] 症状A 症状D [疾病9] 症状B 症状C 症状E [疾病10] 症状B 症状D [疾病11] 症状C 症状D 症状E 六、实验结果 人工智能课内实验报告 (8次) 学 院: 自动化学院 班 级: 智能1501 姓 名: 刘少鹏(34)学 号: 06153034 目 录 课内实验1:猴子摘香蕉问题的VC编程实现„„„„„„„„1 课内实验2:编程实现简单动物识别系统的知识表示„„„5 课内实验3:盲目搜索求解8数码问题„„„„„„„„„18 课内实验4:回溯算法求解四皇后问题„„„„„„„„„33 课内实验5:编程实现一字棋游戏„„„„„„„„„„„37 课内实验6:字句集消解实验„„„„„„„„„„„„„46 课内实验7:简单动物识别系统的产生式推理„„„„„„66 课内实验8:编程实现D-S证据推理算法„„„„„„„„78 人工智能课内实验报告 实验1:猴子摘香蕉问题的VC编程实现 学 院: 自动化学院 班 级: 智能1501 姓 名: 刘少鹏(33)学 号: 06153034 日 期: 2017-3-8 10:15-12:00 实验1:猴子摘香蕉问题的VC编程实现 一、实验目的 (1)熟悉谓词逻辑表示法; (2)掌握人工智能谓词逻辑中的经典例子——猴子摘香蕉问题的编程实现。 二、编程环境 VC语言 三、问题描述 房子里有一只猴子(即机器人),位于a处。在c处上方的天花板上有一串香蕉,猴子想吃,但摘不到。房间的b处还有一个箱子,如果猴子站到箱子上,就可以摸着天花板。如图1所示,对于上述问题,可以通过谓词逻辑表示法来描述知识。要求通过VC语言编程实现猴子摘香蕉问题的求解过程。 图1 猴子摘香蕉问题 四、源代码 #include printf(“Step %d:monkey从%c走到%cn”, ++i, x, y);//x表示猴子的位置,y为箱子的} void Monkey_Move_Box(char x, char y){ 位置 printf(“Step %d:monkey把箱子从%c运到%cn”, ++i, x, y);//x表示箱子的位置,y为} void Monkey_On_Box(){ 香蕉的位置 printf(“Step %d:monkey爬上箱子n”, ++i);} void Monkey_Get_Banana(){ printf(“Step %d:monkey摘到香蕉n”, ++i);} void main(){ unsigned char Monkey, Box, Banana;printf(“********智能1501班**********n”);printf(“********06153034************n”);printf(“********刘少鹏**************n”);printf(“请用a b c来表示猴子箱子香蕉的位置n”);printf(“Monkeytboxtbananan”);scanf(“%c”, &Monkey);getchar();printf(“t”);scanf(“%c”, &Box);getchar();printf(“tt”);scanf(“%c”, &Banana);getchar();printf(“n操作步骤如下n”);if(Monkey!= Box){ Monkey_Go_Box(Monkey, Box);} if(Box!= Banana){ Monkey_Move_Box(Box, Banana);} Monkey_On_Box();Monkey_Get_Banana();printf(“n”); getchar();} 五、实验结果相关截图 六、心得体会 通过本次实验,我初步了学会了使用VC的新建工程,并且进行简单的程序编写。此外我还学会如何使用一些谓词来解决生活中的一些简单问题,并且用VC编程给出具体的操作步骤,感觉对VC编程有了新的认识。在实验中我也遇到过许多问题,比如在我写完代码进行编译时总是会出现一个错误“ fatal error C1010: 在查找预编译头时遇到意外的文件结尾,是否忘记了向源中添加“#include ‘stdafx.h’”关于这个错误我我问了几个同学得不出答案后,我决定通过上网查找,最终找到了解决方法,需要在该项目的每一个cpp结尾的文件属性中设置不使用预编译头即可。在这个过程中也锻炼了自己解决问题的能力。 人工智能课内实验报告 实验2:编程实现简单动物识别系统的知识表示 学 院: 自动化学院 班 级: 智能1501 姓 名: 刘少鹏(33)学 号: 06153034 日 期: 2017-3-13 10:15-12:00 实验2:编程实现简单动物识别系统的知识表示 一、实验目的 1、理解和掌握产生式知识表示方法; 2、能够通过VC编程语言实现产生式系统的规则库。 二、实验内容 1、以动物识别系统的产生式规则为例; 2、用选定的编程语言建造规则库和综合数据库,并能对它们进行增加、删除和修改操作。 三、实验步骤 1、确定需要识别的动物及其属性 本次实验的简单动物识别系统总共能识别7种动物,即:老虎、金钱豹、斑马、长颈鹿、企鹅、鸵鸟和信天翁。 2、建立识别七种动物识别系统的规则 3、选定编程语言并确定综合数据库和规则库结构(1)选用C语言作为编程语言 (2)综合数据库的建立(3)规则库的建立 四、程序源代码 #include { int count;char pre[255];char back[255];int mark;};void check();RULES r[100] = { { 1,“有毛发”,“哺乳动物”,0 }, { 1,“有奶”,“哺乳动物”,0 }, { 1,“有羽毛”,“鸟”,0 }, { 2,“会飞&下蛋&”,“鸟”,0 }, { 1,“吃肉”,“食肉动物”,0 },//所有规则静态数据库 { 3,“有锋利的牙齿&有爪&眼睛盯着前方&”,“食肉动物”,0 }, { 2,“哺乳动物&有蹄&”,“有蹄类哺乳动物”,0 }, { 2,“哺乳动物&反刍&”,“有偶蹄类哺乳动物”,0 }, { 4,“哺乳动物&食肉动物&黄褐色&有暗斑&”,“金钱豹”,0 }, { 4,“哺乳动物&食肉动物&黄褐色&黑色条纹&”,“老虎”,0 }, { 4,“有蹄类哺乳动物&有长脖子&有长腿&有暗斑&”,“长颈鹿”,0 }, { 2,“有蹄类哺乳动物&黑条纹&”,“斑马”,0 }, { 5,“鸟&不会飞&有长脖子&有长腿&黑白色&”,“鸵鸟”,0 }, { 4,“鸟&不会飞&会游泳&黑白色&”,“企鹅”,0 }, { 2,“鸟&会飞&”,“信天翁”,0 }, { 1,“反刍”,“哺乳动物”,0 } };int number;int m;int cat = 15;int a;int length;void input(){ //输入的事实长度 string f[255]; //输入的事实数组 while(1){ cat++;cout << “number” << endl;cin >> r[cat].count;cout << “输入事实,两种以上的事实请在每个事实后加上‘&’符号” << endl;cin >> r[cat].pre;cout << “输入结果” << endl;cin >> r[cat].back;r[cat].mark = 0;while(1){ cout << “输入“1”继续添加规则,输入“2”查看规则库” << endl;int p;cin >> p;if(p == 1){ } else { if(p == 2){ input(); } } check();else { } cout << “输入错误,重新输入” << endl;} } void delate(){ } cout << “输入要删除的条数” << endl;int bar;cin >> bar;for(int t = 0;t <= cat;t++){ r[bar'0' >= 0 && temp[i]'0' >= 0 && temp[j]'0';target[j] = temp[j]3);break;case 2: /* down */ if(blank<6)swap(m + blank, m + blank + 3);break;case 3: /* left */ if(blank!= 0 && blank!= 3 && blank!= 6)swap(m + blank, m + blank1][y1][y-1] =-1; bool flag = true;int i = 0;for(i = 0;i<3;i++)for(int j = 0;j<3;j++)if(s.QP[i][j] == 0)flag = false;if(flag)return NO_BLANK;if(IsWin(s)==-1)return-MAX_NUM;if(IsWin(s)== 1)return MAX_NUM;int count = 0;for(i = 0;i<3;i++) for(int j = 0;j<3;j++) if(s.QP[i][j] == 0)tmpQP[i][j] = 1;else tmpQP[i][j] = s.QP[i][j];for(i = 0;i<3;i++) count +=(tmpQP[i][0] + tmpQP[i][1] + tmpQP[i][2])/ 3;count +=(tmpQP[0][i] + tmpQP[1][i] + tmpQP[2][i])/ 3;for(i = 0;i<3;i++)count +=(tmpQP[0][0] + tmpQP[1][1] + tmpQP[2][2])/ 3;count +=(tmpQP[2][0] + tmpQP[1][1] + tmpQP[0][2])/ 3;for(i = 0;i<3;i++) for(int j = 0;j<3;j++) if(s.QP[i][j] == 0)tmpQP[i][j] =-1;else tmpQP[i][j] = s.QP[i][j];for(i = 0;i<3;i++) count +=(tmpQP[i][0] + tmpQP[i][1] + tmpQP[i][2])/ 3;count +=(tmpQP[0][i] + tmpQP[1][i] + tmpQP[2][i])/ 3;for(i = 0;i<3;i++) count +=(tmpQP[0][0] + tmpQP[1][1] + tmpQP[2][2])/ 3;count +=(tmpQP[2][0] + tmpQP[1][1] + tmpQP[0][2])/ 3;return count;return false;L1: cout << “请输入棋子的坐标xy: ”; }; } else { } cout << “非法输入!”;goto L1;int Tic::s_count = 0;//初始化棋盘状态节点总数,刚开始置为 class demo : public Tic { public: demo(){} bool Judge(){ } virtual bool AutoDone(){ int a, b, i, j, m, n, max, min, x, y;if(IsWin(States[0])==-1){ } a = 0, b = 0;max =-10000;for(x = 0;x<3;x++) for(y = 0;y<3;y++)States[11].QP[x][y] = States[0].QP[x][y];cout << “恭喜您获胜!” << endl;return true;int i, j, a = 0;for(i = 0;i<3;i++)for(j = 0;j<3;j++)if(States[0].QP[i][j] == 0)a++;if(a == 0)return true;return false;for(i = 0;i<3;i++)for(j = 0;j<3;j++){ if(States[0].QP[i][j] == 0){ a = 1; for(x = 0;x<3;x++) for(y = 0;y<3;y++) } } States[a].QP[x][y] = States[0].QP[x][y]; States[a].QP[i][j] = 1;min = 10000; for(m = 0;m<3;m++) for(n = 0;n<3;n++){ } if(States[a].QP[m][n] == 0){ } b = 1; for(x = 0;x<3;x++) for(y = 0;y<3;y++) States[10].QP[x][y] = States[a].QP[x][y]; States[10].QP[m][n] =-1; States[10].e_fun = e_fun(States[10]); if(States[10].e_fun States[a].e_fun = min;if(States[a].e_fun>max){ } max = States[a].e_fun;for(x = 0;x<3;x++) for(y = 0;y<3;y++) States[11].QP[x][y] = States[a].QP[x][y];for(x = 0;x<3;x++)for(y = 0;y<3;y++)States[0].QP[x][y] = States[11].QP[x][y];cout << “计算机走棋” << endl;PrintQP();if(IsWin(States[0])== 1){ } else if(IsWin(States[0])==-1){ } return false; cout << “抱歉你输了,计算机获胜!” << endl;return true;cout << “恭喜您获胜!” << endl;return true; };} void main(){ cout << “****项目名称:一字棋游戏的实现****” << endl;cout << “****班 级:智 能 1 5 0 1 ****” << endl;cout << “****姓 名:刘 少 鹏****” << endl;cout << “****学 号:0 6 1 5 3 0 3 4 ****” << endl;cout << “****说 明:-1代表人落子位置,1代表电脑落子位置,0代表该位置无棋子 ****” << endl; system(“title #子棋智能小游戏”);system(“color A2”);char IsFirst;bool IsFinish;cout << “若您为先手,请输入'Y'!反之,请输入'N':” << endl;cin >> IsFirst;demo *p = new demo();p->init();cout << “棋盘的初始状态:” << endl;p->PrintQP();do { if(!p->Judge()){ } if(p->Judge())IsFinish = true;if(IsFirst == 'Y'){ } else if(IsFirst == 'N'){ } IsFinish = p->AutoDone();if(!p->Judge()){ } if(!IsFinish){ p->UserInput();p->PrintQP();} p->UserInput();p->PrintQP();if(!p->Judge()){ } IsFinish = p->AutoDone();} while(!IsFinish);if((p->IsWin(p->States[0])== 0)&& p->Judge()){ } } cout << “平局” << endl;system(“pause”);3.2、实验运行结果截图 4、实验心得 本次实验,我通过学习用VC编程语言设计简单的博弈游戏,从而理解和掌握博弈树的启发式搜索过程,熟悉博弈中两种最基本的搜索方法——极大极小过程和过程。并且将这种思想通过代码表现出来。 本次实验我最大的收获不仅仅是学到了课本上的知识,更是学会了如何主动的求解问题的答案。实验中我遇到了许多困难,不仅仅是有关编程算法方面的,还有一些代码逻辑流程的设计。这些困难我通过上网和去图书馆查找资料或者向同学请教等方式,逐一解决了困难,我收获良多。 人工智能课内实验报告 实验6:子句集消解实验 学 院: 自动化学院 班 级: 智能1501 姓 名: 刘少鹏(33)学 号: 06153034 日 期: 2017-05-8 10:15-12:00 实验6子句集消解实验 一、实验目的 (1)熟悉子句集化简的九个步骤; (2)理解消解规则,能把任意谓词公式转换成子句集。 二、编程环境 Visual Studio 2017 三、实验原理 在谓词逻辑中,任何一个谓词公式都可以通过应用等价关系及推理规则化成相应的子句集。 其化简步骤如下: (1)消去连接词“→”和“↔” 反复使用如下等价公式: P→Q ⇔﹁ P∨Q P↔Q ⇔(P∧Q)∨(﹁P∧﹁Q)即可消去谓词公式中的连接词“→”和“↔”。(2)减少否定符号的辖域 反复使用双重否定率 ﹁(﹁P)⇔ P 摩根定律 ﹁(P∧Q)⇔﹁P∨﹁Q ﹁(P∨Q)⇔﹁P∧﹁Q 量词转换率 ﹁(∀x)P(x)⇔(∃x)﹁P(x) ﹁(∃x)P(x)⇔(∀x)¬P(x)将每个否定符号“﹁”移到仅靠谓词的位置,使得每个否定符号最多只作用于一个谓词上。 (3)对变元标准化 在一个量词的辖域内,把谓词公式中受该量词约束的变元全部用另外一个没有出现过的任意变元代替,使不同量词约束的变元有不同的名字。 (4)化为前束范式 化为前束范式的方法:把所有量词都移到公式的左边,并且在移动时不能改变其相对顺序。 (5)消去存在量词 (6)化为Skolem标准形 对上述前束范式的母式应用以下等价关系 P∨(Q∧R)⇔(P∨Q)∧(P∨R)(7)消去全称量词(8)消去合取词 在母式中消去所有合取词,把母式用子句集的形式表示出来。其中,子句集中的每一个元素都是一个子句。 (9)更换变量名称 对子句集中的某些变量重新命名,使任意两个子句中不出现相同的变量名。 四、实验结果及代码 //化简子句集的九步法演示 //作者:刘少鹏 //时间:2017.5 #include void initString(string &ini);//初始化 string del_inlclue(string temp);//消去蕴涵符号 string dec_neg_rand(string temp);//减少否定符号的辖域 string standard_var(string temp);//对变量标准化 string del_exists(string temp);//消去存在量词 string convert_to_front(string temp);//化为前束形 string convert_to_and(string temp);//把母式化为合取范式 string del_all(string temp);//消去全称量词 string del_and(string temp);//消去连接符号合取% string change_name(string temp);//更换变量名称 //辅助函数定义 bool isAlbum(char temp);//是字母 string del_null_bracket(string temp);//删除多余的括号 string del_blank(string temp);//删除多余的空格 void checkLegal(string temp);//检查合法性 char numAfectChar(int temp);//数字显示为字符 //主函数 void main(){ cout << “------------------求子句集九步法演示-----------------------” << endl;system(“color 0A”);//orign = “Q(x,y)%~(P(y)”;//orign = “(@x)(P(y)>P)”;//orign = “~(#x)y(x)”;//orign = “~((@x)x!b(x))”;//orign = “~(x!y)”;//orign = “~(~a(b))”;string orign, temp;char command, command0, command1, command2, command3, command4, command5,48 人工智能实验三实验报告 班级: 姓名: 学号: 一 实验题目 TSP问题的遗传算法实现 旅行商问题(Traveling Salesman Problem, TSP),又译为旅行推销员问题、货担郎问题,简称为TSP问题,是最基本的路线问题。假设有n个可直达的城市,一销售商从其中的某一城市出发,不重复地走完其余n-1个城市并回到原出发点,在所有可能的路径中求出路径长度最短的一条。 应用遗传算法求解30/10个节点的TSP(旅行商问题)问题,求问题的最优解。 二 实验目的 熟悉和掌握遗传算法的基本概念和基本思想; 理解和掌握遗传算法的各个操作算子,能够用选定的编程语言设计简单的遗传优化系统; 通过实验培养学生利用遗传算法进行问题求解的基本技能。 三 实验要求 掌握遗传算法的基本原理、各个遗传操作和算法步骤; 2 要求求出问题最优解,若得不出最优解,请分析原因; 对实验中的几个算法控制参数进行仔细定义,并能通过实验选择参数的最佳值; 要求界面显示每次迭代求出的局部最优解和最终求出的全局最优解。 四 数据结构 请说明染色体个体和群体的定义方法。 struct RanSeTi //染色体的个体的定义方法 { int city[cities];//基因的排列(即城市的顺序,路径的组织) int adapt;//记录适应度 double p;//记录其在种群中的幸存概率 } RanSeTi [num], RanSeTi temp[num];//用数组来存储染色体群体方法 五 实验算法 说明算法中对染色体的编码方法,适应度函数定义方法 1)染色体的编码方法: 即为染色体个体定义过程中生成的基因排列(路径中城市的顺序) struct RanSeTi //染色体的个体的定义方法 { int city[cities];//基因的排列(即城市的顺序,路径的组织) int adapt;//记录适应度 double p;//记录其在种群中的幸存概率 } RanSeTi [num], RanSeTi temp[num];//用数组来存储染色体群体方法 2)适应度函数定义方法: 评价函数即适应度函数,在遗传算法中用来计算一个染色体优劣的函数。在进行遗传操作和种群进化的时候,每个染色体的适应值是决定它是否进入下一轮种群进化的关键因素。适应值高的函数被选作新一代个体的可能性就会大。 TSP问题中适应度函数常取路径长度的倒数(或倒数的相关函数),如: f(x1,x2,,xn)N d(x,xii1n1i1)d(xnx1) 其中,N是个调节参数,根据实验情况进行确定。采用的选择、交叉、变异操作算子的具体操作 1)选择操作 我们定义f(xi)为第i(i=1,2,3.....popsize)个染色体的适应度,则每个个体被选中的概率 popsize for(i=0;i n1= RanSeTi [i].city[j-1]; n2= RanSeTi [i].city[j]; sumdistance+=distance[n1][n2];} RanSeTi [i].adapt=sumdistance;//每条染色体的路径总和 biggestsum+=sumdistance;//种群的总路径 } 是: P(xi)f(xi) f(xj1j) 本题中具体使用的是期望值方法 for(i=0;i } gradient[0]=group[0].p;for(i=1;i if(xuanze[i] { xuan[i]=j;//第i个位置存放第j个染色体 break; } } } //拷贝种群 for(i=0;i for(i=0;i 交叉算子就是把两个父代个体的部分结构加以替换重组而生成新个体的操作。部分匹配交叉、顺序交叉、改进的启发式顺序交叉 //temp1号染色体和temp2染色体交配 for(i=0;i { point1=rand()%cities; point2=rand()%cities; for(j=temp1;j if(jiaopeiflag[j]==1) { temp1=j; break; } for(j=temp1+1;j if(jiaopeiflag[j]==1) { temp2=j; break; } //进行基因交配 if(point1>point2)//保证point1<=point2 { temp=point1; point1=point2; point2=temp; } memset(map1,-1,sizeof(map1)); memset(map2,-1,sizeof(map2)); //断点之间的基因产生映射 for(k=point1;k<=point2;k++) { map1[group[temp1].city[k]]=group[temp2].city[k]; map2[group[temp2].city[k]]=group[temp1].city[k]; } //断点两边的基因互换 for(k=0;k { temp=group[temp1].city[k]; group[temp1].city[k]=group[temp2].city[k]; group[temp2].city[k]=temp; } for(k=point2+1;k { temp=group[temp1].city[k]; group[temp1].city[k]=group[temp2].city[k]; group[temp2].city[k]=temp; } //处理产生的冲突基因 for(k=0;k { for(kk=point1;kk<=point2;kk++) if(group[temp1].city[k]==group[temp1].city[kk]) { group[temp1].city[k]=map1[group[temp1].city[k]]; break; } } for(k=point2+1;k { for(kk=point1;kk<=point2;kk++) if(group[temp1].city[k]==group[temp1].city[kk]) { group[temp1].city[k]=map1[group[temp1].city[k]]; break; } } for(k=0;k { for(kk=point1;kk<=point2;kk++) if(group[temp2].city[k]==group[temp2].city[kk]) { group[temp2].city[k]=map2[group[temp2].city[k]]; break; } } for(k=point2+1;k { for(kk=point1;kk<=point2;kk++) if(group[temp2].city[k]==group[temp2].city[kk]) { group[temp2].city[k]=map2[group[temp2].city[k]]; break; } } temp1=temp2+1; } 3)变异操作 TSP问题中,经常采取的变异操作主要有:位点变异、逆转变异、对换变异、插入变异。//随机产生变异概率 srand((unsigned)time(NULL)); for(i=0;i { bianyip[i]=(rand()%100); bianyip[i]/=100; } //确定可以变异的染色体 t=0; for(i=0;i { if(bianyip[i] { bianyiflag[i]=1; t++; } } //变异操作,即交换染色体的两个节点 srand((unsigned)time(NULL)); for(i=0;i { if(bianyiflag[i]==1) { temp1=rand()%10; temp2=rand()%10; point=group[i].city[temp1]; group[i].city[temp1]=group[i].city[temp2]; group[i].city[temp2]=point; } } 实验中采用的算法参数的最佳选择值是多少 #define cities 10/30 //城市的个数 #define MAXX 150 //迭代次数 #define pc 0.72 //交配概率 #define pm 0.02 //变异概率 #define num 20 //种群的大小 六 实验结果 要求有实验运行结果截图,以及必要的说明 以上部分是每次迭代的步骤结果,通过染色体群体中个体的交配、变异,从而更改染色体的具体基因组成,通过不断进行适应度计算、存活率的计算,更新已有数值; 以上部分为迭代之后的总结果,输出最终的种群评价,从染色体种群里面取出最佳的染色体,并进行输出。要求说明是否搜索到了最优解,如果没有,请分析原因 本题中根据随机生成的cities个城市之间的相互距离、随机产生初试群,通过TSP算法,通过以下步骤: (1)初始化群体; (2)计算群体上每个个体的适应度值;(4)按概率Pc进行交叉操作;(5)按概率Pm进行变异操作;(6)没有满足某种停止条件,则转第(2)步,否则进入(7); (7)输出种群中适应度值最优的染色体作为问题的满意解或最优解。 (3)按由个体适应度值所决定的某个规则选择将进入下一代的个体;成功找到种群中适应度值最优的染色体作为问题的满意解或最优解。 若失败,分析可得失败原因为:随机生成的cities个城市之间的相互距离、随机产生初试群有可能不存在适应度值最优的染色体 七 实验总结及体会 1.同一问题可能有不同的几种算法相对应解决: 对于此类旅行者问题,原在数据结构和算法课中学过迪杰斯特拉算法,也可以高效快速的解决给定好初值的最短路径问题; 在本课中,有学到了新的算法:TSP算法,此算法从遗传学角度,开辟了一个新的视野。通过每次迭代求出的局部最优解和最终求出的全局最优解。 两种不同的算法可以求解同一问题,但是角度完全不一样,从目前自己实验的结果而言,对于小数据量的输入均可以快速高效的完成题目。但是遗传算法可以考虑到的问题复杂度更高,更适合应用于实际。 2.学习时应当重视动手实践能力: 课堂上讲解的遗传算法较为简单基础,对于理论学习而言,十分适合。但一旦应用于实践时,发现虽然每个部分模块自己都可以理解并且熟悉,但是对于实际应用,并且切实地解决实际问题仍存在较大的困难。 从理论到实践,从课本的知识到解决问题,若不及时的加以消化并且切实的应用于解决问题,可以看出知识很难为现实提供帮助。因而应在学习之后及时进行上机实验,并且达到熟练掌握与运用的阶段。 《人工智能》实验一题目 实验一 启发式搜索算法 1.实验内容: 使用启发式搜索算法求解8数码问题。 ⑴ 编制程序实现求解8数码问题A算法,采用估价函数 wn,fndnpn其中:dn是搜索树中结点n的深度;wn为结点n的数据库中错放的棋子个数;pn为结点n的数据库中每个棋子与其目标位置之间的距离总和。 ⑵ 分析上述⑴中两种估价函数求解8数码问题的效率差别,给出一个是pn的上界的hn的定义,并测试使用该估价函数是否使算法失去可采纳性。 2.实验目的 熟练掌握启发式搜索A算法及其可采纳性。3.数据结构与算法设计 该搜索为一个搜索树。为了简化问题,搜索树节点设计如下: typedef struct Node//棋盘 {//节点结构体 int data[9];double f,g;struct Node * parent;//父节点 }Node,*Lnode;int data[9];数码数组:记录棋局数码摆放状态。struct Chess * Parent;父节点:指向父亲节点。下一步可以通过启发搜索算法构造搜索树。 1、局部搜索树样例: 2、搜索过程 搜索采用广度搜索方式,利用待处理队列辅助,逐层搜索(跳过劣质节点)。搜索过程如下: (1)、把原棋盘压入队列; (2)、从棋盘取出一个节点; (3)、判断棋盘估价值,为零则表示搜索完成,退出搜索; (4)、扩展子节点,即从上下左右四个方向移动棋盘,生成相应子棋盘; (5)、对子节点作评估,是否为优越节点(子节点估价值小于或等于父节点则为优越节点),是则把子棋盘压入队列,否则抛弃; (5)、跳到步骤(2); 3、算法的评价 完全能解决简单的八数码问题,但对于复杂的八数码问题还是无能为力。现存在的一些优缺点。 1、可以改变数码规模(N),来扩展成N*N的棋盘,即扩展为N数码问题的求解过程。 2、内存泄漏。由于采用倒链表的搜索树结构,简化了数据结构,但有部分被抛弃节点的内存没有很好的处理,所以会造成内存泄漏; 3、采用了屏蔽方向,有效防止往回搜索(节点的回推),但没能有效防止循环搜索,所以不能应用于复杂度较大的八数码问题; 源码: #include typedef struct Node {//节点结构体 int data[9];double f,g;struct Node * parent;}Node,*Lnode; typedef struct Stack {//OPEN CLOSED 表结构体 Node * npoint;struct Stack * next;}Stack,* Lstack; Node * Minf(Lstack * Open){//选取OPEN表上f值最小的节点,返回该节点地址 Lstack temp =(*Open)->next,min =(*Open)->next,minp =(*Open);Node * minx; while(temp->next!= NULL){ if((temp->next->npoint->f)<(min->npoint->f)) { min = temp->next; minp = temp; } temp = temp->next;} minx = min->npoint;temp = minp->next;minp->next = minp->next->next;free(temp);return minx;} int Canslove(Node * suc, Node * goal){//判断是否可解 int a = 0,b = 0,i,j;for(i = 1;i< 9;i++) for(j = 0;j < i;j++) { if((suc->data[i] > suc->data[j])&& suc->data[j]!= 0)a++; if((goal->data[i] > goal->data[j])&& goal->data[j]!= 0)b++; } if(a%2 == b%2)return 1;else return 0;} int Equal(Node * suc,Node * goal){//判断节点是否相等,相等,不相等 for(int i = 0;i < 9;i ++) if(suc->data[i]!= goal->data[i])return 0; return 1;} Node * Belong(Node * suc,Lstack * list){//判断节点是否属于OPEN表或CLOSED表,是则返回节点地址,否则返回空地址 Lstack temp =(*list)-> next;if(temp == NULL)return NULL;while(temp!= NULL){ if(Equal(suc,temp->npoint))return temp-> npoint; temp = temp->next;} return NULL;} void Putinto(Node * suc,Lstack * list){//把节点放入OPEN 或CLOSED 表中 Stack * temp;temp =(Stack *)malloc(sizeof(Stack));temp->npoint = suc;temp->next =(*list)->next;(*list)->next = temp;} ///////////////计算f值部分-开始////////////////////////////// double Fvalue(Node suc, Node goal, int m){//计算f值 switch(m){ case 1:{ int error(Node,Node); int w=0; w=error(suc,goal); return w+suc.g; } case 2:{ double Distance(Node,Node,int); double p = 0; for(int i = 1;i <= 8;i++) p = p + Distance(suc, goal, i); return p + suc.g;//f = h + g; } default: break;} } int error(Node suc,Node goal){//计算错位个数 int w,i;w=0;for(i=0;i<9;i++){ if(suc.data[i]!=goal.data[i]) w++;} return w;} double Distance(Node suc, Node goal, int i){//计算方格的错位距离 int k,h1,h2;for(k = 0;k < 9;k++){ if(suc.data[k] == i)h1 = k; if(goal.data[k] == i)h2 = k;} return double(fabs(h1/3h2%3));} ///////////////计算f值部分-结束////////////////////////////// ///////////////////////扩展后继节点部分的函数-开始///////////////// int BelongProgram(Lnode * suc ,Lstack * Open ,Lstack * Closed ,Node goal ,int m){//判断子节点是否属于OPEN或CLOSED表并作出相应的处理 Node * temp = NULL;int flag = 0;if((Belong(*suc,Open)!= NULL)||(Belong(*suc,Closed)!= NULL)){ if(Belong(*suc,Open)!= NULL)temp = Belong(*suc,Open); else temp = Belong(*suc,Closed); if(((*suc)->g)<(temp->g)) { temp->parent =(*suc)->parent; temp->g =(*suc)->g; temp->f =(*suc)->f; flag = 1; } } else { Putinto(* suc, Open); (*suc)->f = Fvalue(**suc, goal, m);} return flag;} int Canspread(Node suc, int n){//判断空格可否向该方向移动,,表示空格向上向下向左向右移 int i,flag = 0;for(i = 0;i < 9;i++) if(suc.data[i] == 0)break;switch(n){ case 1: if(i/3!= 0)flag = 1;break;case 2: if(i/3!= 2)flag = 1;break;case 3: if(i%3!= 0)flag = 1;break;case 4: if(i%3!= 2)flag = 1;break;default:break;} return flag;} void Spreadchild(Node * child,int n){//扩展child节点的字节点n表示方向,,表示空格向上向下向左向右移 int i,loc,temp;for(i = 0;i < 9;i++) child->data[i] = child->parent->data[i];for(i = 0;i < 9;i++) if(child->data[i] == 0)break;if(n==0) loc = i%3+(i/3-1)*3;else if(n==1) loc = i%3+(i/3 + 1)*3;else if(n==2) loc = i%3-1+(i/3)*3;else loc = i%3+1+(i/3)*3;temp = child->data[loc];child->data[i] = temp;child->data[loc] = 0;} void Spread(Lnode * suc, Lstack * Open, Lstack * Closed, Node goal, int m){//扩展后继节点总函数 int i;Node * child;for(i = 0;i < 4;i++){ if(Canspread(**suc, i+1)) //判断某个方向上的子节点可否扩展 { child =(Node *)malloc(sizeof(Node)); //扩展子节点 child->g =(*suc)->g +1; //算子节点的g值 child->parent =(*suc); //子节点父指针指向父节点 Spreadchild(child, i); //向该方向移动空格生成子节点 if(BelongProgram(&child, Open, Closed, goal, m))// 判断子节点是否属于OPEN或CLOSED表并作出相应的处理 free(child); } } } ///////////////////////扩展后继节点部分的函数-结束////////////////////////////////// Node * Process(Lnode * org, Lnode * goal, Lstack * Open, Lstack * Closed, int m){//总执行函数 while(1){ if((*Open)->next == NULL)return NULL; //判断OPEN表是否为空,为空则失败退出 Node * minf = Minf(Open); //从OPEN表中取出f值最小的节点 Putinto(minf, Closed); //将节点放入CLOSED表中 if(Equal(minf, *goal))return minf; //如果当前节点是目标节点,则成功退出 Spread(&minf, Open, Closed, **goal, m); //当前节点不是目标节点时扩展当前节点的后继节点 } } int Shownum(Node * result){//递归显示从初始状态到达目标状态的移动方法 if(result == NULL)return 0;else { int n = Shownum(result->parent); printf(“第%d步:”,n); for(int i = 0;i < 3;i++) { printf(“n”); for(int j = 0;j < 3;j++) { if(result->data[i*3+j]!= 0) printf(“ %d ”,result->data[i*3+j]); else printf(“ 0 ”); } } printf(“n”); return n+1;} } void Checkinput(Node *suc){//检查输入 int i = 0,j = 0,flag = 0;char c;while(i < 9){ while(((c = getchar())!= 10)) { if(c == ' ') { if(flag >= 0)flag = 0; } else if(c >= '0' && c <= '8') { if(flag == 0) { suc->data[i] =(c-'0'); flag = 1; for(j =0;j < i;j++) if(suc->data[j] == suc->data[i])flag =-2; i++; } else if(flag >= 0)flag =-1; } else if(flag >= 0)flag =-1; } if(flag <0 || i < 9) { if(flag < 0) { if(flag ==-1)printf(“含有非法字符或数字!n请重新输入:n”); else if(flag ==-2)printf(“输入的数字有重复!n请重新输入:n”); } else if(i < 9)printf(“输入的有效数字不够!n请重新输入:n”); i = 0; flag = 0; } } } int meassure(Lstack s){ int k=0;while((s->next)!=NULL){ k++; s=s->next;} return k;} void main(){//主函数 //初始操作,建立open和closed表 Lstack Open =(Stack *)malloc(sizeof(Stack));Open->next = NULL;Lstack Closed =(Stack *)malloc(sizeof(Stack));Closed->next = NULL;Node * org =(Node *)malloc(sizeof(Node));org->parent = NULL; //初始状态节点 org->f =1;org->g =1; Node * goal =(Node *)malloc(sizeof(Node)); //目标状态节点 Node * result;int m;char c;int k; printf(“=================================n”);printf(“说明:状态矩阵由0-8 九个数字表示,n请依次按照九宫格上的行列顺序输入,每个数字间用空格隔开。n”); printf(“=================================n”);printf(“请输入初始状态(0-8 9个数字以空格隔开回车表示输入结束):n”);Checkinput(org);printf(“请输入目标状态(0-8 9个数字以空格隔开回车表示输入结束):n”);Checkinput(goal);if(Canslove(org, goal)){//A*算法开始,先将初始状态放入OPEN表 printf(“请选择:1.按w(n)搜索 2.按p(n)搜索 n”); scanf(“%d”,&m); while((c = getchar())!= 10); printf(“搜索中,请耐心等待(如果您觉得时间太久请重新执行程序并输入更快的速度,默认值为)......n”); Putinto(org,&Open); result = Process(&org, &goal, &Open, &Closed, m);//进行剩余的操作 printf(“总步数:%d”,Shownum(result)-1); printf(“n”); k=meassure(Closed); printf(“扩展节点数:n”); printf(“%dn”,k); printf(“Press Enter key to exit!”); while((c = getchar())!= 10);} else printf(“程序认定该起始状态无法道达目标状态!n”);} 实 验 报 告 【实验名称】______________产生式系统_______________________ 【实验目的】 1.理解产生式系统的结构原理与实际应用。2.掌握产生式规则表示及规则库组建的实现方法。 3.熟悉和掌握产生式系统的运行机制,掌握基于规则推理的基本方法。 【实验原理】 产生式系统用来描述若干个不同的以一个基本概念为基础的系统,这个基本概念就是产生式规则或产生式条件和操作对。在产生式系统中,论域的知识分为两部分:用事实表示静态知识;用产生式规则表示推理过程和行为。 【实验内容】 1.自己建造产生式系统(包括规则库和事实库),然后进行推理,即可以自己输入任何的事实,并基于原有的规则和输入的事实进行推理。 2.建造动物识别系统,能根据输入的动物特征判断是那种动物或给出相应的回答。3.算法设计 ①首先建立事实库 事实库是在程序的开始直接输入的,用户根据需要选择,即要求用户先输入特征个数,然后输入动物的特征,进行识别。如果未识别出来,则可以重新选择,或者退出。 动物的特征如下: 1有奶 2有毛发 3有羽毛 4会飞 5生蛋 6有爪 7有犬齿 8目盯前方 9吃肉 10有蹄 11反刍食物 12黄褐色 13黑色条纹 14黑色斑点 15长腿 16长脖子 17暗斑点 18白色 19不会飞 20黑白色 21会游泳 22善飞 23不怕风浪 24哺乳动物 25鸟 26食肉动物 27有蹄动物 28偶蹄动物 29海燕 30老虎 31金钱豹 32长颈鹿 33斑马 34鸵鸟 35企鹅 ②建立静态规则库 即建立产生式规则,本算法采用了产生中间事实的方法,便于建立和使用规则。为了便于设计,我们把要识别的动物限于7种,这样所需要的产生式规则就比较少。本算法共有15种规则,如下: R1: 如果动物有奶,则它是哺乳动物 R2: 如果动物有毛发,则它是哺乳动物 R3: 如果动物有羽毛,则它是鸟 R4: 如果动物会飞且生蛋,则它是鸟 R5: 吃肉的哺乳动物是食肉动物 R6: 有爪有犬齿木钉前方的哺乳动物是食肉动物 R7: 有蹄的哺乳动物是有蹄动物 R8: 反刍食物的有蹄动物是偶蹄动物 R9: 黄褐色有黑条纹的食肉动物是老虎 R10:黄褐色有黑色斑点的食肉动物是金钱豹 R11:长腿长脖子有黄褐色暗斑点的有蹄动物是长颈鹿 R12:有黑白条纹的有蹄动物是斑马 R13:不会飞长腿长脖的鸟是鸵鸟 R14:不会飞会游泳黑白色的鸟是企鹅 ③正向推理过程 从已知事实出发,通过规则库求得结论,或称数据驱动方式。推理过程是: 规则集中的规则前件与事实库中的事实进行匹配,得匹配的规则集合。 从匹配规则集合中选择一条规则作为使用规则。 执行使用规则的后件,将该使用规则的后件送入事实库中。 重复这个过程直至达到目标。 如有多条匹配规则需从中选一条作为使用规则,本算法是根据规则的顺序依次选择,且规则中不存在同一组事实对应多条匹配规则。 R15:善飞不怕风浪的鸟是海燕 具体表示如下: R1: 1->24 R2: 2->24 R3: 3->25 R4: 4*5->25 R5: 6*7*8*24->26 R6: 9*24->26 R7: 10*24->27 R8: 11*27->28 R9: 12*13*24->30 R10: 12*14*24->31 R11: 12*15*16*17*27->32 R12: 13*18*27->33 R13: 15*16*19*25->34 R14: 19*20*21*25->35 R15: 22*23*25->29 ④实验流程图 开始初始化欲加入的事实的个数及事实令i=1取出规则i的前提条件部分Ni=i+1事实库中有相应的事实Y取出规则i结论部分结论为新事实Y将该规则加入到事实库中该事实是结论性事实Y将该规则的结论作为最终的结论结束NN ⑤实验结果及分析 如输入如下事实:有羽毛、善飞、不怕风浪。系统的推理过程如下: 先从规则库中取出第一条规则R1,检查其前提是否可与事实库中的已知事实相匹配。R1的前提是“有奶”,但事实库中无此事实,故匹配失败;然后取R2,匹配失败;接着取R3,该前提与已知事实“有羽毛”相匹配,故R3被执行,并将其结论“鸟”作为新的事实加入到事实库中。此时,事实库的内容变为:有羽毛、善飞、不怕风浪、鸟;此后,R4~R14均匹配失败,接着取R15,该前提“善飞+不怕风浪+鸟”与已知事实相匹配,R15被执行,并推出“该动物是海燕”。由于“海燕”已是目标集合中的一个结论,即已推出最终结果,故问题求解过程结束。 下面是程序运行的结果: 【实验程序】 #include int i,j,k,a,b,c;int num;int fact[N],temp[N];int flag=1;while(flag==1){ printf(“动物的特征如下:n”);printf(“1有奶 2有毛发 3有羽毛 4会飞 20黑白色n21会游泳 22善飞 23不怕风浪n”); printf(“请输入描述该动物特征的个 数:”); scanf(“%d”,&num); printf(“请输入对这只动物的特征描述的序号(按序号由小到大):n”); for(i=0;i } //********************************for(i=0;i if(fact[i]==1)scanf(“%d”,&a);fact[i]=a;会飞 5生蛋n6有爪 7有犬齿 8目盯前方 9吃肉 10有蹄n11反刍食物 12黄褐色 13黑色条纹 14黑色斑点 15长腿n16长脖子 17暗斑点 18白色 19不 { fact[num]=24;num++;printf(“使用规则1,新增加的 } } //********************************k=0; for(i=0;i } if(temp[0]==4&&temp[1]==5){ fact[num]=25;num++; printf(”使用规则4,新增加的事实if(fact[i]==4){ } if(fact[i]==5){ } temp[k]=fact[i];break;temp[k]=fact[i];k++;continue;事实为: 哺乳动物n“); } //********************************for(i=0;i if(fact[i]==2){ fact[num]=24;num++;printf(”使用规则2,新增加的 } break; 事实为: 哺乳动物n“); } //********************************for(i=0;i if(fact[i]==3){ fact[num]=25;num++;printf(”使用规则3,新增加的 } break; 为:鸟n“); } //******************************** k=0; for(i=0;i if(fact[i]==6)事实为:鸟n”); break; } { } if(fact[i]==7){ } if(fact[i]==8){ } if(fact[i]==24){ } temp[k]=fact[i];break;temp[k]=fact[i];k++;continue;temp[k]=fact[i];k++;continue;temp[k]=fact[i];k++;continue; } //********************************k=0; for(i=0;i } if(temp[0]==9&&temp[1]==24){ fact[num]=26;num++; printf(“使用规则6,新增加的事实if(fact[i]==9){ } if(fact[i]==24){ } temp[k]=fact[i];break;temp[k]=fact[i];k++;continue; 为:食肉动物n”); fact[num]=26;num++;printf(“使用规则5,新增加的事实if(temp[0]==6&&temp[1]==7&&temp[2} //********************************k=0; for(i=0;i if(fact[i]==10){ ]==8&&temp[3]==24) { 为:食肉动物n”); } } temp[k]=fact[i];k++;continue; } } break; if(temp[0]==11&&temp[1]==27){ fact[num]=28;num++; printf(“使用规则8,新增加的事实if(fact[i]==24){ } temp[k]=fact[i];break; 为:偶蹄动物n”); } //********************************k=0; for(i=0;i if(fact[i]==12){ } if(fact[i]==13){ } if(fact[i]==24){ temp[k]=fact[i];break;temp[k]=fact[i];k++;continue;temp[k]=fact[i];k++;continue;if(temp[0]==10&&temp[1]==24){ fact[num]=27;num++;printf(“使用规则7,新增加的事实 为:有蹄动物n”); } //********************************k=0;for(i=0;i if(fact[i]==11){ } if(fact[i]==27){ temp[k]=fact[i]; temp[k]=fact[i];k++;continue; } } } } if(temp[0]==12&&temp[1]==13&&tempif(temp[0]==12&&temp[1]==14&&temp[2]==24) { fact[num]=30;//num++;printf(“使用规则9,新增加的事实 [2]==24) { fact[num]=31;//num++; printf(”使用规则10,新增加的事实为:老虎n该动物为老虎n“); 为:金钱豹n该动物为金钱豹n”); } //********************************k=0; for(i=0;i if(fact[i]==12){ } if(fact[i]==15){ } if(fact[i]==16){ temp[k]=fact[i];k++; temp[k]=fact[i];k++;continue;temp[k]=fact[i];k++;continue;} //********************************k=0;for(i=0;i if(fact[i]==12){ } if(fact[i]==14){ } if(fact[i]==24){ temp[k]=fact[i];break; temp[k]=fact[i];k++;continue; temp[k]=fact[i];k++;continue; } } continue; } } continue;if(fact[i]==17){ } if(fact[i]==27){ } temp[k]=fact[i];break;temp[k]=fact[i];k++;continue; if(fact[i]==18){ } if(fact[i]==27){ } temp[k]=fact[i];break;temp[k]=fact[i];k++;continue; if(temp[0]==12&&temp[1]==15&&tempif(temp[0]==13&&temp[1]==18&&temp[2]==16&&temp[3]==17&&temp[4]==27) { fact[num]=32;//num++;printf(“使用规则11,新增加的事实 [2]==27) { fact[num]=33;//num++; printf(”使用规则12,新增加的事实为:长颈鹿n该动物为长颈鹿n“); 为:斑马n该动物为斑马n”); } //********************************k=0; for(i=0;i if(fact[i]==15){ temp[k]=fact[i];k++;} //********************************k=0;for(i=0;i if(fact[i]==13){ temp[k]=fact[i];k++; } } continue; for(i=0;i } if(temp[0]==19&&temp[1]==20&&temp if(fact[i]==19){ } if(fact[i]==20){ } if(fact[i]==21){ } if(fact[i]==25){ } temp[k]=fact[i];break;temp[k]=fact[i];k++;continue;temp[k]=fact[i];k++;continue;temp[k]=fact[i];k++;continue;if(fact[i]==16){ } if(fact[i]==19){ } if(fact[i]==25){ } temp[k]=fact[i];break;temp[k]=fact[i];k++;continue;temp[k]=fact[i];k++;continue; if(temp[0]==15&&temp[1]==16&&temp[2]==19&&temp[3]==25) { fact[num]=34;//num++;printf(“使用规则13,新增加的事实 为:鸵鸟n该动物为鸵鸟n”); } //********************************k=0; [2]==21&&temp[3]==25) { fact[num]=35; //num++;printf(“使用规则14,新增加的事实 } } 为:企鹅n该动物为企鹅n”); } //********************************k=0;for(i=0;i if(fact[i]==22){ } if(fact[i]==23){ } if(fact[i]==25){ temp[k]=fact[i];break;temp[k]=fact[i];k++;continue;temp[k]=fact[i];k++;continue; if(temp[0]==22&&temp[1]==23&&temp [2]==25) { fact[num]=29;//num++; printf(“使用规则15,新增加的事实 为:海燕n该动物为海燕n”); } //********************************if(fact[num]<29) printf(“现有事实无法推断出结 果!n”); printf(“n”); printf(“继续请按1,退出按其它数字 键:”); } scanf(“%d”,&c);if(c==1) flag=c; else break;} 【小结或讨论】 本系统的规则库是静态的,不能动态增加新的规则。这使得在规则变化的情况下不能及时改变,但是该系统已经能基本满足需要,对输入的事实能给出相应的回答,判断出是何种动物。 读书的好处 1、行万里路,读万卷书。 2、书山有路勤为径,学海无涯苦作舟。 3、读书破万卷,下笔如有神。 4、我所学到的任何有价值的知识都是由自学中得来的。——达尔文 5、少壮不努力,老大徒悲伤。 6、黑发不知勤学早,白首方悔读书迟。——颜真卿 7、宝剑锋从磨砺出,梅花香自苦寒来。 8、读书要三到:心到、眼到、口到 9、玉不琢、不成器,人不学、不知义。 10、一日无书,百事荒废。——陈寿 11、书是人类进步的阶梯。 12、一日不读口生,一日不写手生。 13、我扑在书上,就像饥饿的人扑在面包上。——高尔基 14、书到用时方恨少、事非经过不知难。——陆游 15、读一本好书,就如同和一个高尚的人在交谈——歌德 16、读一切好书,就是和许多高尚的人谈话。——笛卡儿 17、学习永远不晚。——高尔基 18、少而好学,如日出之阳;壮而好学,如日中之光;志而好学,如炳烛之光。——刘向 19、学而不思则惘,思而不学则殆。——孔子 20、读书给人以快乐、给人以光彩、给人以才干。——培根第二篇:人工智能实验报告
第三篇:人工智能TSP旅行商问题实验报告
第四篇:人工智能实验报告-八数码
第五篇:人工智能产生式系统实验报告解读