📄 queen.c
字号:
#include <mpi.h>#include <stdio.h>#define QUEENS 8#define MAX_SOLUTIONS 92typedef int bool;const int true = 1;const int false = 0;/*枚举信号*/enum msg_content{ READY, ACCOMPLISHED, NEW_TASK, TERMINATE};/*枚举信息标签*/enum msg_tag{ REQUEST_TAG, SEED_TAG, REPLY_TAG, NUM_SOLUTIONS_TAG, SOLUTIONS_TAG};int solutions[MAX_SOLUTIONS][QUEENS];int solution_count = 0;/* *函数名:collides *功能:检查两个位置是否有列、对角线或反对角线冲突 *输入:row1为位置1的行号; * col1为位置1的列号; * row2为位置2的行号; * col2为位置2的列号。 *输出:返回1代表两位置有行、对角线或反对角线冲突; * 否则返回0 */bool collides(int row1, int col1, int row2, int col2){ return (col1 == col2) || (col1 - col2 == row1 - row2) || (col1 + row1 == col2 + row2);} /* collides *//* *函数名:generate_seed *功能:生成初始化棋盘,只初始化棋盘的前两列 *输入:无 *输出:返回0代表已没有可初始化的棋盘, * 否则返回生成的初始化的棋盘。 */int generate_seed(){ static int seed = 0; do { seed++; } while (seed <= QUEENS * QUEENS - 1 && collides(0, seed / QUEENS, 1, seed % QUEENS)); if (seed > QUEENS * QUEENS - 1) return 0; else return seed;} /* generate_seed *//* *函数名:print_solutions *功能:打印结果 *输入:count为需要打印的结果的个数; * solutions[][QUEENS]为所要打印出来的结果,即皇后所摆放的位置。 *输出:无 */void print_solutions(int count, int solutions[][QUEENS]){ int i, j, k; for (i = 0; i < count; i++) { /*打印第i+1个结果*/ printf("Solution %d :\n", i + 1); for (j = 0; j < QUEENS; j++) { printf("%d ", solutions[i][j]); /*打印棋盘,*表示皇后所在位置*/ for (k = 0; k < solutions[i][j]; k++) printf("- "); printf("* "); for (k = QUEENS - 1; k > solutions[i][j]; k--) printf("- "); printf("\n"); } printf("\n"); }} /* print_solutions *//* *函数名:is_safe *功能:检查当前皇后所摆放的位置是否与已摆放的皇后的位置相冲突 *输入:chessboard[]为存放皇后所摆放的位置的数组; * row为当前位置的行; * col为当前位置的列。 *输出:返回0代表当前位置有冲突,不可摆放皇后; 返回1代表当前位置没有冲突,可以摆放皇后。 */bool is_safe(int chessboard[], int row, int col){ int i; for (i = 0; i < row; i++) { /*检查当前位置是否与第i行皇后的位置相冲突*/ if (collides(i, chessboard[i], row, col)) return false; } /* for */ return true;} /* is_safe *//* *函数名:place_queens *功能:为当前行的皇后寻找适当的摆放位置, * 如果皇后摆放完毕则记录所摆放的位置, * 递归的摆放后面的皇后, * 当所有皇后摆放完毕后,记录所得的解。 *输入:chessboard[]为存放皇后所摆放位置的数组; row为当前皇后所要摆放的行号。 *输出:无 */void place_queens(int chessboard[], int row){ int i, col; if (row >= QUEENS) /*所有皇后均摆放完毕*/ { /* 结束递归并记录当前解 */ for (i = 0; i < QUEENS; i++) { solutions[solution_count][i] = chessboard[i]; } solution_count++; } else { /*还有皇后没有摆好*/ for (col = 0; col < QUEENS; col++) /*在当前行寻找适当位置摆放皇后*/ { if (is_safe(chessboard, row, col)) /*当前位置不冲突*/ { chessboard[row] = col; /* 在当前位置放置一个皇后 */ place_queens(chessboard, row + 1);/* 递归放置下一个皇后 */ } /* if */ } /* for */ } /* else */} /* place_queens *//* *函数名:sequential_eight_queens *功能:串行地求解八皇后问题,并将解打印出来 *输入:无 *输出:无 */void sequential_eight_queens(){ int chessboard[QUEENS]; solution_count = 0; /*开始求解八皇后问题*/ place_queens(chessboard, 0); /*打印所求结果*/ print_solutions(solution_count, solutions);} /*sequential_eight_queens*//* *函数名:eight_queens_master *功能:生成初始化棋盘,并将其发送给空闲的子进程; * 从子进程中接受并记录解; * 当所有子进程都已终止且没有新的初始化棋盘时,打印所有的解。 *输入:nodes为工作组中进程数 *输出:无 */void eight_queens_master(int nodes){ MPI_Status status; int active_slaves = nodes - 1; // except the master itself int new_task = NEW_TASK; int terminate = TERMINATE; int reply; int child; int num_solutions; int seed; while (active_slaves) /*有未结束的子进程*/ { /*从子进程中接受返回信号*/ MPI_Recv(&reply, 1, MPI_INT, MPI_ANY_SOURCE, REPLY_TAG, MPI_COMM_WORLD, &status); child = status.MPI_SOURCE; if (reply == ACCOMPLISHED) /*子进程已完成求解任务*/ { /* 从子进程接收并记录解 */ MPI_Recv(&num_solutions, 1, MPI_INT, child, NUM_SOLUTIONS_TAG, MPI_COMM_WORLD, &status); if (num_solutions > 0) { MPI_Recv(solutions[solution_count], QUEENS * num_solutions, MPI_INT, child, SOLUTIONS_TAG, MPI_COMM_WORLD, &status); solution_count += num_solutions; } } seed = generate_seed(); /*产生初始棋盘*/ if (seed) /* 还有新的初始棋盘 */ { /* 向子进程发送一个new_task信号 */ MPI_Send(&new_task, 1, MPI_INT, child, REQUEST_TAG, MPI_COMM_WORLD); /* 向子进程发送一个合法的新棋盘 */ MPI_Send(&seed, 1, MPI_INT, child, SEED_TAG, MPI_COMM_WORLD); } else /* 已求出所有解 */ { /* 向子进程发送终止信号 */ MPI_Send(&terminate, 1, MPI_INT, child, REQUEST_TAG, MPI_COMM_WORLD); active_slaves--; } } /* while */ /*打印所有解*/ print_solutions(solution_count, solutions);} /* eight_queens_master *//* *函数名:eight_queens_slave *功能:从主进程接受新的初始化的棋盘; * 在初始化的棋盘基础上求出所有合法的解; * 将求得的解发送给主进程。 *输入:my_rank为子进程在整个工作组中的进程标识符 *输出:无 */void eight_queens_slave(int my_rank){ MPI_Status status; int ready = READY; int accomplished = ACCOMPLISHED; bool finished = false; int request; int seed; int num_solutions = 0; int chessboard[QUEENS]; /*向主进程发送ready信号*/ MPI_Send(&ready, 1, MPI_INT, 0, REPLY_TAG, MPI_COMM_WORLD); while (! finished) /*子进程未终止*/ { /* 从主进程接收消息 */ MPI_Recv(&request, 1, MPI_INT, 0, REQUEST_TAG, MPI_COMM_WORLD, &status); if (request == NEW_TASK) { /* 从主进程接收初始棋盘 */ MPI_Recv(&seed, 1, MPI_INT, 0, SEED_TAG, MPI_COMM_WORLD, &status); /* 在初始棋盘基础上求解 */ chessboard[0] = seed / QUEENS; chessboard[1] = seed % QUEENS; solution_count = 0; place_queens(chessboard, 2); /* 将解发送给主进程 */ /*向主进程发送accomplished信号*/ MPI_Send(&accomplished, 1, MPI_INT, 0, REPLY_TAG, MPI_COMM_WORLD); MPI_Send(&solution_count, 1, MPI_INT, 0, NUM_SOLUTIONS_TAG, MPI_COMM_WORLD); if (solution_count > 0) { MPI_Send(*solutions, QUEENS * solution_count, MPI_INT, 0, SOLUTIONS_TAG, MPI_COMM_WORLD); } } else /* request == TERMINATE */ { /*主进程要求子进程终止*/ finished = true; } } /* whlie */} /* eight_queens_slave *//******************** main ********************//* *函数名:main *功能:启动MPI计算; * 确定进程数和进程标识符; * 调用主进程和从进程程序并行求解八皇后问题。 *输入:argc为命令行参数个数; * argv为每个命令行参数组成的字符串数组。 *输出:返回0代表程序正常结束;否则程序出错。 */int main(int argc, char* argv[]){ int nodes, my_rank; /*初始化*/ MPI_Init(&argc, &argv); /*确定工作组中的进程个数*/ MPI_Comm_size(MPI_COMM_WORLD, &nodes); /*确定自己在工作组中的进程标识符*/ MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); if (nodes == 1) /*只有一个进程时,用串行算法求解*/ { sequential_eight_queens(); } /*并行求解八皇后问题*/ if (! my_rank) { eight_queens_master(nodes); } else { eight_queens_slave(my_rank); } /*结束MPI计算*/ MPI_Finalize(); return 0;} /* main */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -