zoukankan      html  css  js  c++  java
  • 八皇后问题爬山法实现(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("
    ");
    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("
    ");
    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("
    ");
    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("
    ");
    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("
    ");
    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	%d
    ", x, position);
    248     printf("%d
    ", 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	%d
    ", posx, posy);
    252     chess.position[pair[x].key_y].posx = pair[x].key_x;//将皇后的横坐标该为最小碰撞数所在的位置的横坐标
    253     //printf("%d
    ", 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
    ", min);
    294                 //printf("%d	%d
    ", min_x, min_y);
    295                 break;
    296             }
    297         }
    298         break;
    299     }
    300     /*printf("%d	%d
    ", min_x, min_y);
    301     printf("%d
    ", 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
    ", 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
    ", 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("
    ");
    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
    ", 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("
    ");
    635     printf("globalmin=%3.1d
    ", global_collidecount_min.globalmin);//输出最终的最小碰撞次数
    636     output(a);//a数组中记录了爬山过程中,每次棋盘碰撞次数的最小值
    637     printf("
    ");
    638     printf("%d", number);//number为爬山次数
    639     return 0;
    640 }

  • 相关阅读:
    Oracle的启动过程共经历四个阶段:
    Oracle数据库启动原理
    Oracle LISTENER监听文件参数详解及Lsnrctl命令综述
    Oracle TNS简述
    linux 各级目录的作用
    oracle 监听器的工作原理
    插入标识列
    sql server日期格式转换方法大全
    html获取输入的值的问题
    关闭窗口 不弹出提示
  • 原文地址:https://www.cnblogs.com/liweikuan/p/14106517.html
Copyright © 2011-2022 走看看