八皇后问题爬山法实现(C语言)

运行环境VS2019

 

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <time.h>
  4 #include <stdbool.h>    
  5 //
  6 //    编程题
  7 //  爬山法(八皇后问题)
  8 //  
  9 
 10 
 11 //棋子结构体    
 12 //typedef struct Chess * Chess;
 13 
 14 int a[64];//a数组中记录了爬山过程中,每次棋盘碰撞次数的最小值
 15 int array_count = 0; //array_count是a数组中的计数器
 16 int number = 0;//number为爬山次数
 17 
 18  struct Global_Collidecount_min
 19 {
 20     int  mincollidecount[64];           //存放每次搜索后,棋盘上最小碰撞对数。
 21     int  globalmin = -1;
 22 }global_collidecount_min;
 23 
 24   
 25 
 26 typedef struct 
 27 {
 28     int posx;
 29     int posy;
 30     int collidecount;
 31 }Coordinate;
 32 
 33 
 34 typedef struct 
 35 {
 36     int  value;//存储需要比较的数值
 37     Coordinate position[8];//存储棋盘上的坐标。 
 38 }Chess;
 39 
 40 Chess  chess;
 41 
 42 
 43 //地图结构体
 44 typedef struct 
 45 {
 46 
 47     int map[8][8];
 48     int collidecount[8][8];
 49     int collidecount2[8][8];
 50     int collidecount3[8][8];
 51 }Map;
 52 
 53 
 54 //C实现键值对(Map功能)
 55 typedef struct
 56 {
 57     int key_x;
 58     int key_y;
 59     int value;
 60     bool kaiguan;
 61 }Pair;
 62 
 63 
 64 
 65 
 66 Pair pair[64];
 67 Map ditu;
 68 
 69 
 70 
 71 // 初始化地图
 72 void initmap()
 73 {
 74     for (int x = 0; x < 8; x++)
 75         for (int y = 0; y < 8; y++)
 76         {
 77             ditu.map[x][y] = 0;
 78             ditu.collidecount[x][y] = 0;
 79             ditu.collidecount2[x][y] = 0;
 80             ditu.collidecount3[x][y] = 0;
 81         }
 82 }
 83 
 84 
 85 //初始化八皇后,按列赋初值
 86 void  initchess()
 87 {
 88     int y;
 89     for (y = 0; y < 8; y++)
 90     {
 91         int x = rand() % 8;
 92         chess.value = 1;
 93         chess.position[y].posx = x;
 94         chess.position[y].posy = y;
 95         chess.position[y].collidecount = 0;
 96         ditu.map[x][y] = chess.value;//用1表示棋子
 97     }
 98 
 99 
100 }
101 
102 
103 //初始化键值对 
104 void initpair()
105 {
106 
107     for (int i = 0; i < 63; i++)
108     {
109         pair[i].key_x = 0;
110         pair[i].key_y = 0;
111         pair[i].kaiguan = false;
112         pair[i].value = 0;
113     }
114 
115 }
116 
117 
118 
119 
120 //输出地图
121 void outmap()
122 {
123 
124     for (int x = 0; x < 8; x++)
125     {
126         for (int y = 0; y < 8; y++)
127             printf("%3.1d", ditu.map[x][y]);
128         printf("\n");
129     }
130 }
131 
132 
133 //输出棋子位置
134 void outchess()
135 {
136 
137     for (int x = 0; x < 8; x++)
138     {
139 
140         printf("x=%3.1d,y=%3.1d", chess.position[x].posx, chess.position[x].posy);
141         printf("\n");
142     }
143 
144 }
145 
146 
147 
148 void outmap1()
149 {
150 
151     for (int x = 0; x < 8; x++)
152     {
153         for (int y = 0; y < 8; y++)
154             printf("%3.1d", ditu.collidecount[x][y]);
155         printf("\n");
156     }
157 }
158 
159 
160 void outmap2()
161 {
162 
163     for (int x = 0; x < 8; x++)
164     {
165         for (int y = 0; y < 8; y++)
166             printf("%3.1d", ditu.collidecount2[x][y]);
167         printf("\n");
168     }
169 }
170 
171 
172 void outmap3()
173 {
174 
175     for (int x = 0; x < 8; x++)
176     {
177         for (int y = 0; y < 8; y++)
178             printf("%3.1d", ditu.collidecount3[x][y]);
179         printf("\n");
180     }
181 }
182 
183 
184 
185 // 将地图中的碰撞数ditu.collidecount,ditu.collidecount2,ditu.collidecount3置0;
186 void resetcollidecount()
187 {
188     for (int x = 0; x < 8; x++)
189         for (int y = 0; y < 8; y++)
190         {
191             ditu.collidecount[x][y] = 0;
192             ditu.collidecount2[x][y] = 0;
193             ditu.collidecount3[x][y] = 0;
194         }
195 }
196 
197 
198 // 将存储棋盘中最小碰撞数的pair还原
199 void resetpair()
200 {
201 
202     for (int i = 0; i < 63; i++)
203     {
204         pair[i].key_x = 0;
205         pair[i].key_y = 0;
206         pair[i].kaiguan = false;
207         pair[i].value = 0;
208     }
209 
210 }
211 
212 
213 /// <summary>
214 /// 将地图中的碰撞数ditu.collidecount,ditu.collidecount2,ditu.collidecount3置0;
215 /// 将存储棋盘中最小碰撞数的pair还原
216 /// </summary>
217 void  reset()
218 {
219     resetcollidecount();
220     resetpair();
221 }
222 
223 
224 
225 //查看是否与棋盘中皇后位置重复
226 int find(int row, int column)
227 {
228     int m;
229     for (m = 0; m < 8; m++)
230     {
231         int posx = chess.position[m].posx;
232         int posy = chess.position[m].posy;
233         if ((posx == row) && (posy == column))
234             return 0;
235     }
236     return 1;
237 }
238 
239 
240 
241 //随机选取一个最小碰撞数所在的位置,将地图中同列的皇后置0,
242 void randomselect(int position)
243 {
244 
245     srand((int)time(NULL));
246     int x = rand() % position;
247     /*printf("%d\t%d\n", x, position);
248     printf("%d\n", pair[x].key_y);*/
249     int posx = chess.position[pair[x].key_y].posx;//取得同列皇后的横坐标
250     int posy = chess.position[pair[x].key_y].posy;//取得同列皇后的纵坐标
251     //printf("%d\t%d\n", posx, posy);
252     chess.position[pair[x].key_y].posx = pair[x].key_x;//将皇后的横坐标该为最小碰撞数所在的位置的横坐标
253     //printf("%d\n", pair[x].key_x);
254     ditu.map[posx][posy] = 0;//将地图中皇后原位置置0
255     ditu.map[pair[x].key_x][pair[x].key_y] = 1;//将地图中皇后新位置置1
256 }
257 
258 
259 //统计棋盘中最小碰撞数的个数,并将最小碰撞数所在位置和值存到pair键值对中
260 void countmin(int min)
261 {
262     int position = 0;
263     for (int n = 0; n < 8; n++)
264         for (int m = 0; m < 8; m++)
265             if (ditu.collidecount3[n][m] == min)
266             {
267                 pair[position].key_x = n;
268                 pair[position].key_y = m;
269                 pair[position].kaiguan = true;
270                 pair[position].value = min;
271                 position++;
272             }
273 
274     randomselect(position);
275 }
276 
277 
278 
279 
280 //遍历 pair[]数组,找出最小碰撞数
281 int  visit()
282 {
283 
284     int min, min_x, min_y;
285 
286     for (min_x = 0; min_x < 8; min_x++)
287     {
288         for (min_y = 0; min_y < 8; min_y++)
289         {
290             if (find(min_x, min_y))
291             {
292                 min = ditu.collidecount3[min_x][min_y];
293                 //printf("%d\n", min);
294                 //printf("%d\t%d\n", min_x, min_y);
295                 break;
296             }
297         }
298         break;
299     }
300     /*printf("%d\t%d\n", min_x, min_y);
301     printf("%d\n", min);*/
302 
303 
304     for (int i = 0; i < 8; i++)
305         for (int j = 0; j < 8; j++)
306             if (find(i, j))
307             {
308                 if (min > ditu.collidecount3[i][j])
309                     min = ditu.collidecount3[i][j];
310             }
311     //printf("%d\n", min);
312 
313     return min;
314 }
315 
316 
317 
318 
319 
320 int  countcollidecount()
321 {
322     int row, column, count = 0;
323     for (row = 0; row < 8; row++)
324         for (column = 0; column < 8; column++)
325             if (ditu.collidecount2[row][column] != 0)
326                 count += ditu.collidecount2[row][column];
327     return count;
328 }
329 
330 
331 
332 /// <summary>
333 /// 对m列的n位置上的棋子进行检测
334 /// </summary>
335 /// <param name="hang"></param>
336 /// <param name="lie"></param>
337 void  function3(int hang, int lie)
338 {
339     int collidecount = 0;
340     int collidecount2 = 0;
341     //行检测 
342     for (int count = 0; count < 8; count++)
343     {
344         int m, n;
345         int posx = chess.position[count].posx;
346         int posy = chess.position[count].posy;
347         //printf("x=%d,y=%d\n", posx, posy);
348         for (m = 0; m < 8; m++)
349         {
350             if ((ditu.map[posx][m] != 0) && (m != posy))
351             {
352                 collidecount++;
353 
354             }
355             else
356                 continue;
357         }
358 
359 
360 
361 
362         //lie列             
363         for (n = 0; n < 8; n++)
364         {
365             if ((ditu.map[n][posy] != 0) && (n != posx))
366             {
367                 collidecount++;
368             }
369             else
370                 continue;
371         }
372 
373         //dui'jiao'xian对角线 
374 
375         n = posx - 1; m = posy + 1;
376         {    for (; (n != -1) && (m != 8); n--, m++)
377             if (ditu.map[n][m] != 0)
378                 collidecount++;
379         }   
380 
381         n = posx + 1; m = posy - 1;
382         {    for (; (n != 8) && (m != -1); n++, m--)
383             if (ditu.map[n][m] != 0)
384                 collidecount++; 
385         } 
386         n = posx - 1; m = posy - 1;
387 
388         {    for (; (n != -1) && (m != -1); n--, m--)
389             if (ditu.map[n][m] != 0)
390                 collidecount++;       
391         }   
392 
393         n = posx + 1; m = posy + 1;
394         {    for (; (n != 8) && (m != 8); n++, m++)
395             if (ditu.map[n][m] != 0)
396                 collidecount++;
397         ditu.collidecount2[posx][posy] += collidecount;
398         }     collidecount = 0;
399 
400 
401 
402     }
403 
404     ditu.collidecount3[hang][lie] = countcollidecount();
405 
406 
407     //置零 
408     for (int n = 0; n < 8; n++)
409     {
410         for (int m = 0; m < 8; m++)
411         {
412             ditu.collidecount2[n][m] = 0;
413         }
414     }
415 
416 }
417 
418 
419 
420 /// <summary>
421 /// 检查同列中其他位置上的碰撞数
422 /// </summary>
423 void function2()
424 {
425     for (int n = 0; n < 8; n++)
426         for (int m = 0; m < 8; m++)
427         {
428 
429             if (!find(n, m))
430                 continue;
431             else
432             {
433                 int posx = chess.position[m].posx;
434                 int posy = chess.position[m].posy;
435                 ditu.map[posx][posy] = 0;//将第m列的皇后置0
436                 ditu.map[n][m] = 1;//将m列的第n个位置变为1
437                 chess.position[m].posx = n;
438                 chess.position[m].posy = m;
439                 outmap();
440                 outmap3();
441                 function3(n, m);//对m列n位置碰撞检测
442                 printf("\n");
443                 ditu.map[posx][posy] = 1; //恢复皇后
444                 ditu.map[n][m] = 0;
445                 chess.position[m].posx = posx;
446                 chess.position[m].posy = posy;
447             }
448         }
449 
450 }
451 
452 
453 
454 //碰撞对数检测 
455 void function1()
456 {
457     int collidecount = 0;
458 
459     //行检测 
460     for (int count = 0; count < 8; count++)
461     {
462         int m, n;
463         int posx = chess.position[count].posx;
464         int posy = chess.position[count].posy;
465         //printf("x=%d,y=%d\n", posx, posy);
466         for (m = 0; m < 8; m++)
467         {
468             if ((ditu.map[posx][m] != 0) && (m != posy))
469             {
470                 collidecount++;
471 
472             }
473             else
474                 continue;
475         }
476 
477 
478 
479         //lie列             
480         for (n = 0; n < 8; n++)
481         {
482             if ((ditu.map[n][posy] != 0) && (n != posx))
483             {
484                 collidecount++;
485             }
486             else
487                 continue;
488         }
489 
490         //对角线检测
491         n = posx - 1; m = posy + 1;
492         {    for (; (n != -1) && (m != 8); n--, m++)
493             if (ditu.map[n][m] != 0)
494                 collidecount++;
495         }
496 
497         n = posx + 1; m = posy - 1;
498         {    for (; (n != 8) && (m != -1); n++, m--)
499             if (ditu.map[n][m] != 0)
500                 collidecount++;
501         }
502         n = posx - 1; m = posy - 1;
503 
504         {    for (; (n != -1) && (m != -1); n--, m--)
505             if (ditu.map[n][m] != 0)
506                 collidecount++;
507         }
508 
509         n = posx + 1; m = posy + 1;
510         {    for (; (n != 8) && (m != 8); n++, m++)
511             if (ditu.map[n][m] != 0)
512                 collidecount++;
513         chess.position[count].collidecount += collidecount;
514         }     collidecount = 0;
515 
516     }
517     for (int count = 0; count < 8; count++)
518     {
519         int posx = chess.position[count].posx;
520         int posy = chess.position[count].posy;
521         ditu.map[posx][posy] = chess.position[count].collidecount;
522     }
523 
524 }
525 
526 
527 
528 
529 
530 //输出数组
531 void output(int* array)
532 {
533     for (int i = 0; i <= 63; i++)
534     {
535         printf("%4.1d", array[i]);
536     }
537 }
538 
539 
540 void   output_globalcollidecount()
541 {
542     for (int i = 0; i <= 63; i++)
543     {    //if(global_collidecount_min.mincollidecount[i]!=-1)
544         printf("%4.1d", global_collidecount_min.mincollidecount[i]);
545     }
546 
547 }
548 
549 
550 
551 //初始化碰撞数
552 void init_globalcollidecount()
553 {
554     for (int i = 0; i <= 63; i++)
555     {
556         global_collidecount_min.mincollidecount[i] = -1;
557     }
558 }
559 
560 
561 
562 
563 
564 //存储棋盘中除皇后位置之外,最小的碰撞数
565 void save_mincollidecount(int global_min)
566 {
567     if (global_collidecount_min.globalmin == -1)
568     {
569         global_collidecount_min.globalmin = global_min;
570         global_collidecount_min.mincollidecount[0] = global_min;
571     }
572     else
573     {
574         
575         global_collidecount_min.mincollidecount[number] == global_min;
576 
577 
578 
579         if (global_min < global_collidecount_min.globalmin)
580             global_collidecount_min.globalmin = global_min;//棋盘上,每次检测中的最小碰撞数
581     }
582 }
583 
584 
585 
586 //如果碰撞数不小于之前所有棋盘检测的最小碰撞数,返回0,爬山法终止
587 int find_global_collidecount(int global)
588 {
589 
590     
591     //global是第一次存入,或者global比global_collidecount_min.globalmin还小
592     if ((global_collidecount_min.globalmin == -1) || (global < global_collidecount_min.globalmin))
593     {
594         a[array_count++] = global;
595         save_mincollidecount(global);
596         return 1;
597     }
598     else
599         return 0;
600 }
601 
602 
603 
604 
605 void  HillClimbing()
606 {
607     int min;
608     initmap();       //初始化地图
609     initpair();      //初始化键值对
610     srand((int)time(NULL));     //随机种子
611     initchess();         //初始化棋盘
612     function1();          //碰撞对数检测
613     function2();    //对除皇后外的其他位置进行碰撞检测,将检测值存于ditu.collidecount3
614     min = visit(); //找出ditu.collidecount3中,皇后之外区域内的最小碰撞数
615 
616 
617     while (find_global_collidecount(min))//如果碰撞数不小于之前所有棋盘检测的最小碰撞数,返回0,爬山法终止
618     {
619         number++;
620         countmin(min);   //统计棋盘中最小碰撞数的个数,并将最小碰撞数所在位置和值存到pair键值对中
621         reset();        //将地图中的碰撞数ditu.collidecount,ditu.collidecount2,ditu.collidecount3置0;将存储棋盘中最小碰撞数的pair[]还原(置0)
622         function1();     //碰撞对数检测
623         function2();     // 检查同列中其他位置上的碰撞数
624         min = visit();   //遍历 pair[]数组,找出最小碰撞数
625     }
626 }
627 
628 
629 
630 int main()
631 {
632     init_globalcollidecount();//初始化碰撞数
633     HillClimbing();//爬山法
634     printf("\n");
635     printf("globalmin=%3.1d\n", global_collidecount_min.globalmin);//输出最终的最小碰撞次数
636     output(a);//a数组中记录了爬山过程中,每次棋盘碰撞次数的最小值
637     printf("\n");
638     printf("%d", number);//number为爬山次数
639     return 0;
640 }

 

posted @ 2020-12-09 00:48  liweikuan  阅读(542)  评论(0编辑  收藏  举报