A*算法实现猎人渡河问题


  1 问题描述:
  2  猎人、狗、男人带着男孩1、男孩2,女人带着女孩1、女孩2,一共8个体。一艘小船,一次只能过两个个体,狗和四个小孩不会划船。
  3  注意:
  4 (1)猎人不在,狗咬任何人;
  5 (2)男人不在,女人打男孩;
  6 (3)女人不在,男人打女孩
  7 /*思路:用0表示在此岸,1表示在对岸(0,0,0,0,0,0,0,0,0)分别表示猎人,男人
  8 女人,狗狗,女孩,女孩,男孩,男孩,船在此岸。在满足条件是进行状态转移确定
  9 状态结点信息*/
 10 #include<iostream>
 11 #include<stdlib.h>
 12 #include"A_Def.h"
 13 #include"A_Algo.h"
 14 int main() {
 15     system("Color B5");
 16     int begin[9] = {0,0,0,0,0,0,0,0,0};
 17     int end[9] = {1,1,1,1,1,1,1,1,1};
 18     A_Star(begin,end);
 19     return 0;
 20 }
 21 using namespace std;
 22 void create(Astar &Head) {//创建一个初始化链表
 23     Head = (Astar)(malloc(sizeof(AS)));
 24     Head->next = NULL;
 25 }
 26 int Is_Empety(Astar Head) {//判断表是否为空
 27     if (Head->next!=NULL) return 1;
 28     else return 0;
 29 }
 30 int Is_SomeBefor(Astar Sstar, Astar Head) {//判断新生成的结点是否与其
 31 //上一状态的祖辈有相同的状态
 32     int i;
 33     while (Head!=NULL) {
 34         for (i = 0; i <= 8; i++) {
 35             if (Sstar->t[i] != Head->t[i])
 36                 break;
 37         }
 38         if (i == 9) return 1;
 39         Head = Head->parents;
 40     }return 0;
 41 }
 42 int Is_OK(Astar A) {//判断是否满足转移条件
 43     int F = 1;
 44     //if (A->t[0] != A->t[3]) F = 0;
 45     if((A->t[0]&&!A->t[3]&&(!A->t[1]||!A->t[2]||!A->t[4]||!A->t[5]||!A- >t[6]||!A->t[7]))||(!A->t[0]&&A->t[3]&&(A->t[1]||A->t[2]||A->t[4]||
46 A->t[5]||A->t[6]||A->t[7])))
48
F=0; 49 if((A->t[1] && !A->t[2] && (!A->t[6] || !A->t[7]))|| (!A->t[1]&& A->t[2] && (A->t[6] || A->t[7]))) 51 F=0; 52 if((A->t[2] && !A->t[1] && (!A->t[4] || !A->t[5])) || (!A->t[2] && A->t[1] (A->t[4] || A->t[5]))) 54 F=0; 55 return F; 56 } 57 void Add_Open(Astar &Open,Astar &Check) {//将f排序加入 58 Astar p, q; 59 p = Open; 60 q = Open->next;// 61 while (q!=NULL&&q->f<Check->f) { 62 p = q; 57 63 Check->next = p->next; 64 p->next = Check; 65 } 66 int G_value(Astar Sstar, Astar& Head) {//计算初始结点到当前考察的实际代价 67 if (Head==NULL) Sstar->g = 0; 68 else { 69 Sstar->g = Head->g + 1; 70 } 71 return Sstar->g; 72 } 73 int H_value(Astar Sstar) {//计算当前结点到目标结点的yuce值 核心2 74 int sum = 0; 75 if (!Sstar->t[8]) { 76 for (int i = 0; i <= 7; i++) { 77 if (!Sstar->t[i]) 78 sum++; 79 } 80 if (sum >= 2) { 81 Sstar->h = (sum - 2) * 2 + 1; 82 return Sstar->h; 83 } 84 else { Sstar->h = 1; return 1; } 85 } 86 else 87 { 88 for (int i = 0; i <= 7; i++) { 89 if (!Sstar->t[i]) 90 sum++; 91 } 92 93 Sstar->h = 2*sum; 94 return Sstar->h; 95 } 96 } 97 void Open_EnterFirst(int begin[],int end[]) {//Open表加入第一个结点 98 Astar Open_First=Astar(malloc(sizeof(AS))); 99 Open_First->parents = NULL; 100 Open_First->chilren = NULL; 101 Astar Q = NULL; 102 for (int i = 0; i <= 8; i++) Open_First->t[i] = begin[i]; 103 Open_First->next = NULL; 104 Open_First->g = G_value(Open_First, Q); 105 Open_First->h = H_value(Open_First); 106 Open_First->f = Open_First->g + Open_First->h; 107 Add_Open(Open, Open_First); 108 } 109 void Out(Astar Head,Astar& H) {//从表中取出结点类似于尾插法取出 110 if (!Is_Empety(Head)) { 111 H = NULL; 112 return; 113 } 114 H = Head->next; 115 Head->next = Head->next->next; 116 H->next = NULL; 117 } 118 void Enter_Close(Astar Sstar, Astar& Check_L) {//待考察结点进入Close中或普通结点进普通表 119 Sstar->next = Check_L->next; 120 Check_L->next = Sstar; 121 } 122 void Out_Path(Astar A_Check) {//输出最快渡河的方案lujin 123 cout << "渡河代价:" << A_Check->f << endl; 124 //Astar A_Check1 = A_Check->next; 125 int i = 0; 126 while (A_Check) { 127 if (A_Check->parents) {//确保运行成功 128 for (i = 0; i <= 8; i++) { 129 cout << A_Check->t[i] << " "; 130 if (i == 8) { 131 int p = 1; 132 if (!A_Check->parents->t[8]) { 133 for (int q = 0; q <= 7; q++) { 134 if (!A_Check->parents->t[q]) {//至少为0才过去 135 if (A_Check->t[q] != A_Check->parents->t[q]) {//与下一个状态不相等才过去 136 if (p == 1) cout << "<----"; 137 if (q == 0) cout << "猎人" << "过河" <<" " ; 138 if (q == 1) cout << "男人" << "过河" << " "; 139 if (q == 2) cout << "女人" << "过河" << " "; 140 if (q == 3) cout << "狗狗" << "过河" << " "; 141 if (q == 4) cout << "女孩" << "过河" << " "; 142 if (q == 5) cout << "女孩" << "过河" << " "; 143 if (q == 6) cout << "男孩" << "过河" << " "; 144 if (q == 7) cout << "男孩" << "过河" << " "; 145 p++; 146 } 147 else continue; 148 } 149 else continue; 150 } 151 } 152 else 153 { 154 int r = 1; 155 for (int q = 0; q <= 7; q++) { 156 if (A_Check->parents->t[q]) {//至少为1才过去 157 158 if (A_Check->t[q] != A_Check->parents->t[q]) {//与下一个状态不相等才过去 159 if (r == 1) cout << "<----"; 160 if (q == 0) cout << "猎人" << "回去" << " "; 161 if (q == 1) cout << "男人" << "回去" << " "; 162 if (q == 2) cout << "女人" << "回去" << " "; 163 if (q == 3) cout << "狗狗" << "回去" << " "; 164 r++; 165 } 166 else continue; 167 } 168 else continue; 169 } 170 } 171 } 172 } 173 cout << endl; 174 A_Check = A_Check->parents; 175 } 176 } 177 } 178 int Is_In(Astar A_Check_L_One,Astar Check,Astar &M,Astar &N) {//判断某结点状态在哪个表中 179 int i; 180 N = Check; 181 Check = Check->next; 182 while (Check !=NULL) { 183 for ( i = 0; i <= 8; i++) { 184 if (A_Check_L_One->t[i] != Check->t[i]) 185 break; 186 } 187 if (i == 9) 188 { 189 M = Check; 190 return 1; 191 } 192 N = Check; 193 Check = Check->next; 194 } 195 return 0; 196 } 197 int Is_Same(Astar A, Astar Sstar) {//同一层是否重复 198 int i = 0; 199 A = A->next; 200 while (A) { 201 for (i = 0; i <= 8; i++) { 202 //cout << A->t[i] << "==" << Sstar->t[i] ; 203 if (A->t[i] != Sstar->t[i]) 204 break; 205 } 206 if (i == 9) return 1; 207 A = A->next; 208 } 209 return 0; 210 } 211 void A_Check_LS(Astar A_Check_L, Astar A_Check) {//通过将上一个状态传过来来实现状态转移并且确定状态结点信息(g,h,f),状态转移设置两种方式-->2*2=4//细节较多 212 //Astar Sstar = (Astar)malloc(sizeof(AS)); 213 //Astar Sstar1 = (Astar)malloc(sizeof(AS)); 214 int t0 ; 215 //for (int i = 0; i <= 8; i++) cout << A_Check->t[i] << "++";; cout << endl; 216 int t1[9], t2[9]; 217 for (int i = 0; i <= 8; i++) t2[i] = A_Check->t[i]; 218 if (!A_Check->t[8]) { t0 = 1; 219 for (int i = 0; i <= 2; i++) { 220 for (int i = 0; i <= 8; i++) A_Check->t[i] = t2[i];//操作之前 221 for (int i = 0; i <= 2; i++) { if (!A_Check->t[i]) t0++; } 222 if (t0 != 1 ) {//细节 判断是否有大人 223 if (!A_Check->t[i]) 224 A_Check->t[i] = 1; 225 else continue; 226 for (int i = 0; i <= 8; i++) t1[i] = A_Check->t[i];//操作之后 227 for (int j = 0; j <= 7; j++) { 228 for (int i = 0; i <= 8; i++) A_Check->t[i] = t1[i];//操作之前 229 if (i == j) continue; 230 if (!A_Check->t[j]) 231 A_Check->t[j] = 1; 232 else continue; 233 //Astar A_Check_Check;//判断对面的是否也符合 234 if (Is_OK(A_Check)) { 235 Astar Sstar = (Astar)malloc(sizeof(AS)); 236 for (int i = 0; i <= 8; i++) Sstar->t[i] = A_Check->t[i]; 237 Sstar->t[8] = 1;//细节必须在IF的上面 238 if (Is_SomeBefor(Sstar, A_Check->parents) || Is_Same(A_Check_L, Sstar)) free(Sstar); 239 else 240 { 241 Sstar->chilren = NULL; 242 Sstar->parents = A_Check; 243 Sstar->next = NULL; 244 Sstar->f = G_value(Sstar, A_Check) + H_value(Sstar); 245 for (int i = 0; i <= 8; i++) A_Check->t[i] = t2[i];// cout << Sstar->f<<"++"<<Sstar->parents->g<<"++"<<Sstar->h<<" "; 246 Enter_Close(Sstar, A_Check_L); //for (int i = 0; i <= 8; i++) cout << A_Check->t[i] << "<<++<"; cout << endl; 247 } 248 } 249 } 250 } 251 else break; 252 } 253 for (int i = 0; i <= 8; i++) A_Check->t[i] = t2[i]; 254 for (int i = 0; i <= 2; i++) { 255 for (int i = 0; i <= 8; i++) A_Check->t[i] = t2[i]; 256 if (!A_Check->t[i]) 257 A_Check->t[i] = 1; 258 else continue; 259 if (Is_OK(A_Check)) 260 { 261 Astar Sstar1 = (Astar)malloc(sizeof(AS)); 262 for (int i = 0; i <= 8; i++) Sstar1->t[i] = A_Check->t[i]; 263 Sstar1->t[8] = 1; 264 if (Is_SomeBefor(Sstar1, A_Check->parents) || Is_Same(A_Check_L, Sstar1)) free(Sstar1); 265 else 266 { 267 Sstar1->chilren = NULL; 268 Sstar1->parents = A_Check; 269 Sstar1->next = NULL; 270 Sstar1->f = G_value(Sstar1, A_Check) + H_value(Sstar1); 271 for (int i = 0; i <= 8; i++) A_Check->t[i] = t2[i];// cout << Sstar1->f << "--" << Sstar1->g << "--" << Sstar1->h << " "; 272 Enter_Close(Sstar1, A_Check_L); 273 } 274 } 275 } 276 } 277 278 else { 279 for (int i = 0; i <= 2; i++) { 280 for (int i = 0; i <= 8; i++) A_Check->t[i]=t2[i]; 281 { 282 if (A_Check->t[i]) 283 A_Check->t[i] = 0; 284 else continue; 285 } 286 287 if (Is_OK(A_Check)) { 288 Astar Sstar = (Astar)malloc(sizeof(AS)); 289 for (int i = 0; i <= 8; i++) Sstar->t[i] = A_Check->t[i]; 290 Sstar->t[8] = 0; 291 if (Is_SomeBefor(Sstar, A_Check->parents) || Is_Same(A_Check_L, Sstar)) free(Sstar); 292 else 293 { 294 Sstar->chilren = NULL; 295 Sstar->parents = A_Check; 296 Sstar->next = NULL; 297 Sstar->f = G_value(Sstar, A_Check) + H_value(Sstar); 298 for (int i = 0; i <= 8; i++) A_Check->t[i] = t2[i]; //cout << Sstar->f << "**" << Sstar->g << "**" << Sstar->h << " "; 299 Enter_Close(Sstar, A_Check_L);// for (int i = 0; i <= 8; i++) //cout<< Sstar->t[i]<<"<<<"; cout << endl; 300 } 301 } 302 //for (int i = 0; i <= 8; i++) A_Check->t[i]=t2[i]; 303 } 304 for (int i = 0; i <= 8; i++) A_Check->t[i]=t2[i] ; 305 A_Check->t[8] = 1; 306 for (int i = 0; i <= 2; i++) { 307 for (int i = 0; i <= 8; i++) A_Check->t[i]=t2[i]; 308 if (!A_Check->t[i]) continue; 309 else 310 A_Check->t[i] = 0; 311 for (int i = 0; i <= 8; i++) t1[i] = A_Check->t[i]; 312 for (int j = 0; j <= 3; j++) { 313 if (i==j) continue; 314 for (int i = 0; i <= 8; i++) A_Check->t[i]=t1[i]; 315 if (!A_Check->t[j]) continue; 316 else 317 A_Check->t[j] = 0; 318 if (Is_OK(A_Check)) { 319 Astar Sstar1 = (Astar)malloc(sizeof(AS)); 320 for (int i = 0; i <= 8; i++) Sstar1->t[i] = A_Check->t[i]; 321 Sstar1->t[8] = 0; 322 if (Is_SomeBefor(Sstar1, A_Check->parents )|| Is_Same(A_Check_L, Sstar1)) free(Sstar1); 323 else 324 { 325 Sstar1->chilren = NULL; 326 Sstar1->parents = A_Check; 327 Sstar1->next = NULL; 328 Sstar1->f = G_value(Sstar1, A_Check) + H_value(Sstar1); 329 for (int i = 0; i <= 8; i++) A_Check->t[i] = t2[i];// cout << Sstar1->f << "//" << Sstar1->g << "//" << Sstar1->h << " "; 330 Enter_Close(Sstar1, A_Check_L);// for (int i = 0; i <= 8; i++) // cout<< Sstar1->t[i]<<"<<<"; cout << endl; 331 } 332 } 333 } 334 } 335 }for (int i = 0; i <= 8; i++) A_Check->t[i] = t2[i]; 336 } 337 int Is_Over(Astar Over) { 338 int i; 339 for (i = 0; i <= 8; i++) 340 if (!Over->t[i]) { 341 break; 342 } 343 if (i == 9) return 1; 344 return 0; 345 } 346 void A_Star(int begin[],int end[]) {//核心 1 347 Astar A_Check=NULL; 348 Astar Check_A=NULL; 349 Astar A_Check_L; 350 Astar A_Check_L_One; 351 //Astar A_ChuanChuan;//串串儿 一串到底 352 Astar M = NULL; 353 Astar N = NULL; 354 //A_ChuanChuan = NULL; 355 int F=0,f=0; 356 create(Open); 357 create(Close); 358 create(A_Check_L); 359 Open_EnterFirst(begin,end); 360 while (Is_Empety(Open)) { 361 Out(Open, A_Check); 362 Enter_Close(A_Check, Close); 363 if (Is_Over(A_Check)) { F = 1; break; } 364 A_Check_LS(A_Check_L, A_Check); 365 /* 366 while (Is_Empety(A_Check_L)) 367 { 368 Out(A_Check_L, A_Check_L_One);cout<< "++"; //测验 369 } 370 */ 371 while (Is_Empety(A_Check_L)) 372 { 373 Out(A_Check_L, A_Check_L_One); 374 if (Is_In(A_Check_L_One, Open, M, N)) 375 { 376 377 if (M->g > A_Check_L_One->g) 378 { 379 M->parents = A_Check_L_One->parents; 380 M->g = A_Check_L_One->g; 381 M->f = A_Check_L_One->f; 382 } 383 } 384 else if (Is_In(A_Check_L_One, Close, M, N)) 385 { 386 if (M->g > A_Check_L_One->g) 387 { 388 389 Astar Q; 390 M->parents = A_Check_L_One->parents; 391 M->g = A_Check_L_One->g; 392 M->f = A_Check_L_One->f; 393 M->chilren = NULL; 394 Out(Close, Q); 395 Add_Open(Open, Q); 396 } 397 } 398 else 399 { 400 401 Add_Open(Open, A_Check_L_One); 402 } 403 } 404 405 } if(F) 406 Out_Path(A_Check); 407 } 408 typedef struct A { 409 int t[9]; 410 struct A* next; 411 struct A* parents; 412 struct AA* chilren; 413 int f; 414 int g; 415 int h; 416 } AS, * Astar; 417 typedef struct AA { 418 struct AA* next; 419 struct A* To_A;; 420 }AAS,*AAstar; 421 Astar Open; 422 Astar Close;

 


第1步:猎人和狗过河
第2步:猎人回来
第3步:猎人带一个女儿过河
第4步:猎人和狗回来
第5步:女人带另外一个女孩过河
第6步:女人回来
第7步:男人和女人过河(还要把船带回来,所以男人得过去)
第8步:男人过来
第9步:猎人和狗过去
第10步:女人回来
第11步:女人和男人过河
第12步:男人回来
第13步:男人带一个男孩过河
第14步:猎人和狗回去
第15步:猎人和男孩过河
第16步:猎人回去
第17步:猎人和狗过来

这个猎人渡河问题本身挺简单的,但要用A*算法实现起来并不太简单,因为细节实在太多。另外这题的转态结点在OPEN表和CLOUED表中的并不多,这使得一些Astar算法中的必须要的操作在这里并没有起到作用,所以这个并不是Astar算法的一个典型问题。那为啥我还要写这个呢?我们小唐老师在讲Astar算法时说谁要是用Astar算法写出这个,谁期末就不用考了。所以我就搞起来了,,。

 

posted @ 2020-04-13 22:24  VL_L_^_^  阅读(577)  评论(0)    收藏  举报