queen.c
上传用户:hhyinxing
上传日期:2013-09-10
资源大小:833k
文件大小:9k
源码类别:

并行计算

开发平台:

Unix_Linux

  1. #include <mpi.h>
  2. #include <stdio.h>
  3. #define QUEENS 8
  4. #define MAX_SOLUTIONS 92
  5. typedef int bool;
  6. const int true = 1;
  7. const int false = 0;
  8. /*枚举信号*/
  9. enum msg_content
  10. {
  11.     READY,
  12.     ACCOMPLISHED,
  13.     NEW_TASK,
  14.     TERMINATE
  15. };
  16. /*枚举信息标签*/
  17. enum msg_tag
  18. {
  19.     REQUEST_TAG,
  20.     SEED_TAG,
  21.     REPLY_TAG,
  22.     NUM_SOLUTIONS_TAG,
  23.     SOLUTIONS_TAG
  24. };
  25. int solutions[MAX_SOLUTIONS][QUEENS];
  26. int solution_count = 0;
  27. /*
  28.  *函数名:collides
  29.  *功能:检查两个位置是否有列、对角线或反对角线冲突
  30.  *输入:row1为位置1的行号;
  31.  *      col1为位置1的列号;
  32.  *      row2为位置2的行号;
  33.  *      col2为位置2的列号。
  34.  *输出:返回1代表两位置有行、对角线或反对角线冲突;
  35.  *      否则返回0
  36.  */
  37. bool collides(int row1, int col1, int row2, int col2)
  38. {
  39.     return (col1 == col2)
  40.         || (col1 - col2 == row1 - row2)
  41.         || (col1 + row1 == col2 + row2);
  42. }                                                 /* collides */
  43. /*
  44.  *函数名:generate_seed
  45.  *功能:生成初始化棋盘,只初始化棋盘的前两列
  46.  *输入:无
  47.  *输出:返回0代表已没有可初始化的棋盘,
  48.  *      否则返回生成的初始化的棋盘。
  49.  */
  50. int generate_seed()
  51. {
  52.     static int seed = 0;
  53.     do
  54.     {
  55.         seed++;
  56.     } while (seed <= QUEENS * QUEENS - 1
  57.         && collides(0, seed / QUEENS, 1, seed % QUEENS));
  58.     if (seed > QUEENS * QUEENS - 1)
  59.         return 0;
  60.     else
  61.         return seed;
  62. }                                                 /* generate_seed */
  63. /*
  64.  *函数名:print_solutions
  65.  *功能:打印结果
  66.  *输入:count为需要打印的结果的个数;
  67.  *      solutions[][QUEENS]为所要打印出来的结果,即皇后所摆放的位置。
  68.  *输出:无
  69.  */
  70. void print_solutions(int count, int solutions[][QUEENS])
  71. {
  72.     int i, j, k;
  73.     for (i = 0; i < count; i++)
  74.     {
  75. /*打印第i+1个结果*/
  76.         printf("Solution %d :n", i + 1);
  77.         for (j = 0; j < QUEENS; j++)
  78.         {
  79.             printf("%d ", solutions[i][j]);
  80. /*打印棋盘,*表示皇后所在位置*/
  81.             for (k = 0; k < solutions[i][j]; k++) printf("- ");
  82.             printf("* ");
  83.             for (k = QUEENS - 1; k > solutions[i][j]; k--) printf("- ");
  84.             printf("n");
  85.         }
  86.         printf("n");
  87.     }
  88. }                                                 /* print_solutions */
  89. /*
  90.  *函数名:is_safe
  91.  *功能:检查当前皇后所摆放的位置是否与已摆放的皇后的位置相冲突
  92.  *输入:chessboard[]为存放皇后所摆放的位置的数组;
  93.  *      row为当前位置的行;
  94.  *      col为当前位置的列。
  95.  *输出:返回0代表当前位置有冲突,不可摆放皇后;
  96.         返回1代表当前位置没有冲突,可以摆放皇后。
  97.  */
  98. bool is_safe(int chessboard[], int row, int col)
  99. {
  100.     int i;
  101.     for (i = 0; i < row; i++)
  102.     {
  103. /*检查当前位置是否与第i行皇后的位置相冲突*/
  104.         if (collides(i, chessboard[i], row, col))
  105.             return false;
  106.     }                                             /* for */
  107.     return true;
  108. }                                                 /* is_safe */
  109. /*
  110.  *函数名:place_queens
  111.  *功能:为当前行的皇后寻找适当的摆放位置,
  112.  *      如果皇后摆放完毕则记录所摆放的位置,
  113.  *      递归的摆放后面的皇后,
  114.  *      当所有皇后摆放完毕后,记录所得的解。
  115.  *输入:chessboard[]为存放皇后所摆放位置的数组;
  116.         row为当前皇后所要摆放的行号。
  117.  *输出:无
  118.  */
  119. void place_queens(int chessboard[], int row)
  120. {
  121.     int i, col;
  122.     if (row >= QUEENS)                            /*所有皇后均摆放完毕*/
  123.     {
  124. /* 结束递归并记录当前解 */
  125.         for (i = 0; i < QUEENS; i++)
  126.         {
  127.             solutions[solution_count][i] = chessboard[i];
  128.         }
  129.         solution_count++;
  130.     }
  131.     else
  132.     {
  133. /*还有皇后没有摆好*/
  134.         for (col = 0; col < QUEENS; col++)        /*在当前行寻找适当位置摆放皇后*/
  135.         {
  136.             if (is_safe(chessboard, row, col))    /*当前位置不冲突*/
  137.             {
  138.                 chessboard[row] = col;            /* 在当前位置放置一个皇后 */
  139.                 place_queens(chessboard, row + 1);/* 递归放置下一个皇后 */
  140.             }                                     /* if */
  141.         }                                         /* for */
  142.     }                                             /* else */
  143. }                                                 /* place_queens */
  144. /*
  145.  *函数名:sequential_eight_queens
  146.  *功能:串行地求解八皇后问题,并将解打印出来
  147.  *输入:无
  148.  *输出:无
  149.  */
  150. void sequential_eight_queens()
  151. {
  152.     int chessboard[QUEENS];
  153.     solution_count = 0;
  154. /*开始求解八皇后问题*/
  155.     place_queens(chessboard, 0);
  156. /*打印所求结果*/
  157.     print_solutions(solution_count, solutions);
  158. }                                                 /*sequential_eight_queens*/
  159. /*
  160.  *函数名:eight_queens_master
  161.  *功能:生成初始化棋盘,并将其发送给空闲的子进程;
  162.  *      从子进程中接受并记录解;
  163.  *      当所有子进程都已终止且没有新的初始化棋盘时,打印所有的解。
  164.  *输入:nodes为工作组中进程数
  165.  *输出:无
  166.  */
  167. void eight_queens_master(int nodes)
  168. {
  169.     MPI_Status status;
  170.     int active_slaves = nodes - 1;                // except the master itself
  171.     int new_task = NEW_TASK;
  172.     int terminate = TERMINATE;
  173.     int reply;
  174.     int child;
  175.     int num_solutions;
  176.     int seed;
  177.     while (active_slaves)                         /*有未结束的子进程*/
  178.     {
  179. /*从子进程中接受返回信号*/
  180.         MPI_Recv(&reply, 1, MPI_INT, MPI_ANY_SOURCE, REPLY_TAG, MPI_COMM_WORLD, &status);
  181.         child = status.MPI_SOURCE;
  182.         if (reply == ACCOMPLISHED)                /*子进程已完成求解任务*/
  183.         {
  184. /* 从子进程接收并记录解 */
  185.             MPI_Recv(&num_solutions, 1, MPI_INT, child, NUM_SOLUTIONS_TAG, MPI_COMM_WORLD, &status);
  186.             if (num_solutions > 0)
  187.             {
  188.                 MPI_Recv(solutions[solution_count],
  189.                     QUEENS * num_solutions, MPI_INT,
  190.                     child, SOLUTIONS_TAG, MPI_COMM_WORLD, &status);
  191.                 solution_count += num_solutions;
  192.             }
  193.         }
  194.         seed = generate_seed();                   /*产生初始棋盘*/
  195.         if (seed)                                 /* 还有新的初始棋盘 */
  196.         {
  197. /* 向子进程发送一个new_task信号 */
  198.             MPI_Send(&new_task, 1, MPI_INT, child, REQUEST_TAG, MPI_COMM_WORLD);
  199. /* 向子进程发送一个合法的新棋盘 */
  200.             MPI_Send(&seed, 1, MPI_INT, child, SEED_TAG, MPI_COMM_WORLD);
  201.         }
  202.         else                                      /* 已求出所有解 */
  203.         {
  204. /* 向子进程发送终止信号 */
  205.             MPI_Send(&terminate, 1, MPI_INT, child, REQUEST_TAG, MPI_COMM_WORLD);
  206.             active_slaves--;
  207.         }
  208.     }                                             /* while */
  209. /*打印所有解*/
  210.     print_solutions(solution_count, solutions);
  211. }                                                 /* eight_queens_master */
  212. /*
  213.  *函数名:eight_queens_slave
  214.  *功能:从主进程接受新的初始化的棋盘;
  215.  *      在初始化的棋盘基础上求出所有合法的解;
  216.  *      将求得的解发送给主进程。
  217.  *输入:my_rank为子进程在整个工作组中的进程标识符
  218.  *输出:无
  219.  */
  220. void eight_queens_slave(int my_rank)
  221. {
  222.     MPI_Status status;
  223.     int ready = READY;
  224.     int accomplished = ACCOMPLISHED;
  225.     bool finished = false;
  226.     int request;
  227.     int seed;
  228.     int num_solutions = 0;
  229.     int chessboard[QUEENS];
  230. /*向主进程发送ready信号*/
  231.     MPI_Send(&ready, 1, MPI_INT, 0, REPLY_TAG, MPI_COMM_WORLD);
  232.     while (! finished)                            /*子进程未终止*/
  233.     {
  234. /* 从主进程接收消息 */
  235.         MPI_Recv(&request, 1, MPI_INT, 0, REQUEST_TAG, MPI_COMM_WORLD, &status);
  236.         if (request == NEW_TASK)
  237.         {
  238. /* 从主进程接收初始棋盘 */
  239.             MPI_Recv(&seed, 1, MPI_INT, 0, SEED_TAG, MPI_COMM_WORLD, &status);
  240. /* 在初始棋盘基础上求解 */
  241.             chessboard[0] = seed / QUEENS;
  242.             chessboard[1] = seed % QUEENS;
  243.             solution_count = 0;
  244.             place_queens(chessboard, 2);
  245. /* 将解发送给主进程 */
  246.             /*向主进程发送accomplished信号*/
  247.             MPI_Send(&accomplished, 1, MPI_INT, 0, REPLY_TAG, MPI_COMM_WORLD);
  248.             MPI_Send(&solution_count, 1, MPI_INT, 0, NUM_SOLUTIONS_TAG, MPI_COMM_WORLD);
  249.             if (solution_count > 0)
  250.             {
  251.                 MPI_Send(*solutions,
  252.                     QUEENS * solution_count,
  253.                     MPI_INT, 0, SOLUTIONS_TAG, MPI_COMM_WORLD);
  254.             }
  255.         }
  256.         else                                      /* request == TERMINATE */
  257.         {
  258. /*主进程要求子进程终止*/
  259.             finished = true;
  260.         }
  261.     }                                             /* whlie */
  262. }                                                 /* eight_queens_slave */
  263. /******************** main ********************/
  264. /*
  265.  *函数名:main
  266.  *功能:启动MPI计算;
  267.  *      确定进程数和进程标识符;
  268.  *      调用主进程和从进程程序并行求解八皇后问题。
  269.  *输入:argc为命令行参数个数;
  270.  *      argv为每个命令行参数组成的字符串数组。
  271.  *输出:返回0代表程序正常结束;否则程序出错。
  272.  */
  273. int main(int argc, char* argv[])
  274. {
  275.     int nodes, my_rank;
  276. /*初始化*/
  277.     MPI_Init(&argc, &argv);
  278. /*确定工作组中的进程个数*/
  279.     MPI_Comm_size(MPI_COMM_WORLD, &nodes);
  280. /*确定自己在工作组中的进程标识符*/
  281.     MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
  282.     if (nodes == 1)                               /*只有一个进程时,用串行算法求解*/
  283.     {
  284.         sequential_eight_queens();
  285.     }
  286. /*并行求解八皇后问题*/
  287.     if (! my_rank)
  288.     {
  289.         eight_queens_master(nodes);
  290.     }
  291.     else
  292.     {
  293.         eight_queens_slave(my_rank);
  294.     }
  295. /*结束MPI计算*/
  296.     MPI_Finalize();
  297.     return 0;
  298. }                                                 /* main */