傳教士與野人過河問題(A*搜索 C++)


傳教士與野人過河問題:

任意時刻,左岸、右岸、船上如果傳教士人數少於野人人數,傳教士就會被野人吃掉。當然野人會划船。傳教士人數為0也是可以的。

啟發函數 f=g+h.  g當前結點所在解空間樹的深度。h=m+c-2*b. m,c分別是當前狀態下左岸傳教士和野人的數目。b=1表示當前船在左岸停靠。b=0表示當前狀態船在右岸。

#include<vector>
#include<algorithm> #include<stdio.h> #include<stdlib.h> using namespace std; #define MAXM 5 #define MAXC 5 typedef struct Node { int M, C, B; int g, h, f; int parent;//記錄父節點在tree中的下標 }Node; vector<Node> open; vector<Node> close; vector<Node> tree; Node boat[8] = { { 0,1,1,0,0,0,-1 }, { 0,2,1,0,0,0,-1 }, { 0,3,1,0,0,0,-1 }, { 1,0,1,0,0,0,-1 }, { 1,1,1,0,0,0,-1 }, { 2,0,1,0,0,0,-1 }, { 2,1,1,0,0,0,-1 }, { 3,0,1,0,0,0,-1 } }; void show_open() {//顯示open表 vector<Node>::iterator ite; ite = open.end()-1; for (; ite >=open.begin(); ite--) { printf("(%d,%d,%d,%d,%d,%d)\n", (*ite).M, (*ite).C, (*ite).B, (*ite).g, (*ite).h, (*ite).f); if (ite == open.begin()) break; } } void show_close() {//顯示close表 vector<Node>::iterator ite; ite = close.begin(); for (; ite < close.end(); ite++) { printf("(%d,%d,%d,%d,%d,%d)\n", (*ite).M, (*ite).C, (*ite).B, (*ite).g, (*ite).h, (*ite).f); } } bool operator ==(Node a, Node b) { return(a.M == b.M&&a.C == b.C&&a.B == b.B); } bool exit_open(Node p) {//判斷節點是否存在open表中 if(find(open.begin(), open.end(), p)==open.end()) return false; else return true; } bool exit_close(Node p) {//判斷節點是否存在close表中 if (find(close.begin(), close.end(), p) == close.end()) return false; else return true; } bool comp(Node a, Node b) { return a.f > b.f;//根據估價函數值降序排列 } void add_open(Node p) {//open表添加  open.push_back(p); sort(open.begin(), open.end(), comp);//默認升序排列,這里comp按降序排列 } void add_close(Node p) {//close表添加  close.push_back(p); } void out_open() {//open表刪除  open.pop_back(); } bool judge_Node(Node p) {//判斷狀態p是否合法 if (p.M > MAXM || p.C > MAXC || p.M < 0 || p.C < 0)//不在范圍內。不合法 return false; /*if (((p.M >= p.C) && (MAXM - p.M >= MAXC - p.C)) || (p.M == MAXM) || (p.M == 0)) return true; return false;*/ else if (p.M != 0 && p.M < p.C)//左岸傳教士人數不為0 並且小於野人數 return false; else if (MAXM - p.M != 0 && MAXM - p.M < MAXC - p.C)//右岸傳教士人數不為0就算了 居然比野人數少!!當然不行 return false; else return true; } void expand(Node p) {//對節點p進行擴展  Node q; printf("------------------------------------------------------------------------------------\n"); printf("\t\t\t對結點: "); printf("( %d %d %d )進行擴展\n", p.M, p.C, p.B); for (int i = 0; i < 8; i++) { if (p.B == 1) {//p船在左岸 q.M = p.M - boat[i].M; q.C = p.C - boat[i].C; q.B = p.B - boat[i].B; } else {//p船在右岸 q.M = p.M + boat[i].M; q.C = p.C + boat[i].C; q.B = p.B + boat[i].B; } if (judge_Node(q) && !exit_open(q) && !exit_close(q)) {//避免死循環 已經擴展過的結點不再擴展 q.g = p.g + 1; q.h = q.M + q.C - 2 * q.B; q.f = q.g + q.h; int pos = find(tree.begin(), tree.end(), p)-tree.begin(); q.parent = pos; printf("擴展出新的子結點:"); printf("(%d,%d,%d,%d,%d,%d)\n",q.M,q.C,q.B,q.g,q.h,q.f); add_open(q); tree.push_back(q); } else { printf("\t------節點(%d,%d,%d)不滿足條件,擴展失敗------\n", q.M, q.C, q.B); } } printf("\t\t=======================================================\n"); add_close(p); printf("\t\t\t\t******open表狀態******\n"); show_open(); printf("\t\t\t\t******close表狀態******\n"); show_close(); printf("------------------------------------------------------------------------------------\n"); } bool destination(Node p) {//判斷p是否為目標節點 if (p.M == 0 && p.C == 0 && p.B == 0) return true; else return false; } Node solve() { Node p{ 5, 5, 1, 0, 10, 10,-1 }; open.push_back(p); tree.push_back(p); char c; Node x; while (open.size() != 0) { x = *(open.end() - 1);//從open表中取出一個進行擴展 if (destination(x)) return x;//如果是目標狀態 則結束 out_open();//從open中刪除 expand(x);//擴展該結點 //getchar();  } //return NULL; } void path(Node p) { vector<Node> temp; while (p.parent!=-1) { temp.push_back(p); p = tree[p.parent]; } temp.push_back(p); vector<Node>::iterator ite1 = temp.end() - 1; for (; ite1 >= temp.begin(); ite1--) { printf("(%d,%d,%d,%d,%d,%d)\n", (*ite1).M, (*ite1).C, (*ite1).B, (*ite1).g, (*ite1).h, (*ite1).f); if (ite1 == temp.begin()) break; } } int main() { Node goal=solve(); printf("求得傳教士與野人過河問題狀態空間的一個解為:\n"); path(goal); }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM