MPI计算N皇后问题

使用MPI计算N皇后问题。

要求:

N>8,进(线)程数P取等于N,小于N,大于N等不同情况。

现有的一些实现中存在部分问题;
八皇后问题mpi求解方案 该文章中无法实现进程数和N不相等情况,而且在输出文件过程中没有进行进程同步,导致输出结果不全或者乱序。
高性能计算:使用MPI多进程并行求解N皇后,并按进程顺序输出摆放方案该文章进行了部分改进,可以按照顺序输出N皇后的排列方案,但是仍然无法实现N不等于P的情况。

本文所做的工作

对上述两个blog的代码进行改进,实现了计算过程中支持进(线)程数P取等于N,小于N,大于N等不同情况。并且可以按照进程号的顺序输出排列结果。
主要是为每个进程划分任务,当进程数大于N时,有部分进程不参与N皇后排列。当进程数小于N时,每个进程对应着在第一行棋盘放多个皇后的情况(原来是每个进程只管在第一行棋盘放一个的情况)。

代码实现

n_queue.cpp

//#include "stdafx.h"

#include <chrono>
#include <cstring>
#include <chrono>
#include <cstring>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <thread>
#include <cmath>
#ifndef MPICH_SKIP_MPICXX
#define MPICH_SKIP_MPICXX
#endif
#include <mpi.h>

using std::cout;

using std::endl;

using std::clog;

using std::ofstream;

using std::ifstream;
using std::ostringstream;
using std::string;

#define N 8

double start_time,end_time;

void outPut(const int & size,int *  array,ostringstream & file)//输出到文件

{

     //MPI_File_write_at()
     //MPI_File_write_ordered(mpi_file,&endl, 1, MPI_CHAR, MPI_STATUS_IGNORE);


     for(int i = 0 ; i < size ; i++)

     {

         file<<array[i]<<"  ";


     }


     file<<endl;

}

 

bool isContact(const int &deep, const int * const &array)//判断对角线上是否有冲突

{

     int temp;

     for(int i = 1 ; i < deep+1 ; i++)

     {

         temp = array[deep-i];

         if(array[deep] -i == temp || array[deep] + i == temp )//这条语句完成判断

              return true;

     }

     return false;

}

 

 

void range(const int & size, const int &deep,int * const &flags,int *  &array,int &count, ostringstream &file)//进行递归推导

{

     for(int i = 0 ; i < size ; i++)//从第到第个,判断是否还有没用过并且没有冲突的数据

     {

         if(!flags[i])//判断是否被用过,这里使用的是按内容寻址的方式

         {

 

              array[deep] = i;//如果i没有被使用过,那么现在使用i

              if(deep !=0)//不是第一行的元素要判断对角线上是否有冲突

              {

                   if(isContact(deep,array))//判断对角线是否有冲突,主要deep是层次

                       continue;//如果有冲突,继续循环,寻找下一个试探点

              }

              flags[i] = 1;//目前第i个点可用,这里进行标记,第i个点已经被占用了

              if(deep == size-1)//当深度为,就是找到了一个序列,满足八皇后要求了

              {

                   outPut(size,array,file);//将结果输出到文件

                   count++;//次数加一

              }

              else//没有找全所有的棋子

              {

                   range(size,deep+1,flags,array,count,file);//进一步递归调用,完成没完成的棋子

                   array[deep] = -1;//递归回来,要恢复原状,以备下次继续递归到新的序列

              }

         flags[i] = 0;//恢复标志

         }

     }

}

 

void mpi_range(const int & size,int *  &flags,int *  &array,const int &start,int &end,int myId)//mpi开启递归调用

{

     //ofstream file;

     int count = 0 ;//计数为
     int totalCount = 0;//总计数为
     ostringstream file;


     if(start>=N)goto need_not_compute;

     //file.open("temp.txt",std::ios::out | std::ios::app);//输出的文件,每个进程都以追加的方式存放数据

     flags = new int[N];//两个数据结构,flags用来存储位置是否被占用信息

     array = new int[N];//存储第i行的棋子放的位置

     memset(flags,0,sizeof(int)*N);//赋初值

     memset(array,-1,sizeof(int)*N);

     for(int i = start;i<end;++i)
     {
          flags[i] = 1;//当第一行放i的情况
          array[0] = i;
          range(N,1,flags,array,count,file);//开始递归
          memset(flags,0,sizeof(int)*N);//清零
          memset(array,-1,sizeof(int)*N);
     }
     //file.close();
     need_not_compute:
     MPI_Reduce(&count,&totalCount,1,MPI_INT,MPI_SUM,0,MPI_COMM_WORLD);//规约所有递归结构
     end_time = MPI_Wtime();
     MPI_Status status;
     int deley = 0;
     if (myId == 0)
     {
          cout<<"cout: "<<totalCount<<endl;
          cout<<"using time: "<<end_time-start_time<<endl;

          cout << file.str();
          // cout<<myId;
          MPI_Send(&deley, 1, MPI_INT, myId + 1, 0, MPI_COMM_WORLD);
     }
    if (myId >= 1)
     {
          MPI_Recv(&deley, 1, MPI_INT, myId - 1, 0, MPI_COMM_WORLD, &status);
          cout << file.str();
          //  cout<<myId;
          if (myId + 1 < size)
          {
               MPI_Send(&deley, 1, MPI_INT, (myId + 1) % size, 0, MPI_COMM_WORLD);
          }
     }
         


}

 

 

int main(int argc, char* argv[])

{

     int size;

     int myId;

     //ofstream file;

     MPI_Init(&argc,&argv);//初始化mpi

     MPI_Comm_size(MPI_COMM_WORLD,&size);//获取开启的进程数量

     MPI_Comm_rank(MPI_COMM_WORLD,&myId);//获取当前进程的id号

 

     int *flags;//标记

     int *array;//存放棋盘次序

     //file.open("temp.txt");//用来清空文件--采用一次打开然后关闭文件,仅仅是在计算前,清空文件中原有的内容,后面文件打开均采用追加的方式

     //file.close();

     //划分每个进程的任务
     int block = ceil(N*1.0/size);
     int start = myId*block;  
     int end = myId==size-1?N:(myId+1)*block;
     //防止end超出界限
     end = end>N?N:end;
     start_time=MPI_Wtime();
     mpi_range(size,flags,array,start,end,myId);//开始递归计算

     MPI_Finalize();//计算终止

     return 0;

}

makefile

SRC=n_queue.cpp
OBJ=n_queue
CC=mpicxx
#CFLAGS

$(OBJ):$(SRC)
	$(CC) $(SRC) -o $(OBJ) -lm
run:
	mpirun -np 10 ./$(OBJ)
	
.PHONY : clean
clean:
	rm $(OBJ)
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值