问题描述
实现n皇后问题,利用概率算法和回溯法,只需找到一组解。
算法思想
回溯法思想即将第i个皇后摆放在第i行,从1开始,每个皇后都从第1列开始尝试。判断在该列摆放皇后是否与前面的皇后有冲突,如果没有冲突,则在该列摆放皇后,并置放下一个皇后;如果有冲突,则考虑下一列。如果该行没有合适的位置,回溯到上一个皇后,在原来位置的下一个位置上继续尝试摆放皇后,直到找到所有合理摆放方案。
但是当皇后数量较多时,仅仅使用回溯法非常耗时,所以考虑使用概率算法随机置放皇后。如果皇后全部使用概率算法放置,随机性导致效率不是很高,所以选择使用lv算法放置前sv个皇后,剩下的皇后采用回溯法放置。
完整代码
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <iostream>
#define MAX 500
using namespace std;
//判断第i个皇后的位置是否合法,合法返回1,否则返回0
int check(int r[MAX],int i,int j){
//r[MAX]表示第i个皇后所在的列,(i,j)表示皇后的位置
int k;
for(k=0;k<i;k++){
if(r[k]==j){
return 0;
}
if(r[k]-k==j-i){
return 0;
}
if(r[k]+k==i+j){
return 0;
}
}
return 1;
}
//输出n皇后的位置
void print(int r[MAX],int n){
//r[MAX]表示第i个皇后所在的列,n表示皇后个数
int i,j;
int count=0;
for(i=0;i<n;i++){
cout<<"第"<<count+1<<"个皇后放在第"<<r[i]+1<<"列"<<endl;
count++;
}
cout<<endl;
cout<<"得到的矩阵如下所示"<<endl;
for(i=0;i<n;i++){
for(j=0;j<n;j++){
if(r[i]==j){
printf("1 ");
}
else{
printf("0 ");
}
}
cout<<endl;
}
}
//回溯法放置第sv个开始的皇后
int backtrace(int r[MAX],int n,int start){
int i=start;
int j=0;
int num=0;//记录成功放置的皇后
while(1){
while(j<n){
if(check(r,i,j)){
break;//找到了放置第sv个皇后的位置
}
j++;
}
if(j<n){
r[i++]=j;//成功放置,记录位置
j=0;
}
else{
j=r[--i]+1;//如果没有找到,返回上一个皇后,将其位置后移一位
}
if(i==n && r[i-1]<n){
j=r[--i]+1;
num++;
return num;//找到了解
}
else if(i<start){
break;//没有找到解
}
}
return num;
}
//前sv个皇后的lv算法
int lv(int r[MAX], int n, int sv){
int k;
int count=0;
for(int i=0;i<n;i++){
r[i]=0;
}
for(int i=0;i<n;i++){
int j=rand()%n+1;
count=count+1;
if(check(r,i,j)){
r[i]=j;
count=0;
}
if(count==n){
return 0;
}
}
backtrace(r,n,sv);
}
int main(){
int n, sv;
cout<<"请输入皇后的个数(n>=8):";
cin>>n;
cout<<"请输入用LV算法进行放置的皇后个数(stopVegas):";
cin>>sv;
srand((unsigned int)time(NULL));
int r[MAX];
while(lv(r,n,sv)==0){//循环结束直到找到解
//print(results,n);
}
print(r,n);
return 0;
}