// HomeWork_P72.cpp : 此文件包含 "main" 函數。程序執行將在此處開始並結束。
//
#include "pch.h"
#include <iostream>
#include <vector>
#include <random>
#include <ctime>
#include <time.h>
#include <set>
#include <sys/timeb.h>
#include <sys/utime.h>
using namespace std;
#define NUMOFQUEEN 20//12~20
//檢查是否合法
bool isOk(int x, int y, vector<vector<int>> chessBox) {
//檢查列
for (int i = 0; i < NUMOFQUEEN; ++i)
if (chessBox[i][y] == 1)
return false;
//檢查135度和45度方向
for(int i=0;i< NUMOFQUEEN;++i)
for (int j = 0; j < NUMOFQUEEN; ++j) {
if (chessBox[i][j] == 1) {
if (i - j == x - y || i + j == x + y)
return false;
}
}
return true;
}
//回溯法求八皇后
void backTrack(vector<vector<int>> &chessBox) {
int i = 0, j = 0;
vector<int> stack;//保存列號
int searchNode = 0;//搜索節點數
while (i < NUMOFQUEEN) {
bool findJ = false;
for (; j < NUMOFQUEEN; ++j)
if (isOk(i, j, chessBox)==true) {
findJ = true;
break;
}
if (findJ) {
chessBox[i][j] = 1;//放置皇后
++searchNode;
stack.push_back(j);//將當前列入棧
++i;
j = 0;
}
else {
--i;
j = *(--stack.end());//回溯到上一行j
stack.pop_back();//列出棧
chessBox[i][j] = 0;
j++;//從當前列的下一列開始
}
}
cout << "搜索節點數: " << searchNode << endl;
}
//打印結果
void print(vector<vector<int>> chessBox) {
for (auto ii : chessBox) {
for (auto jj : ii) {
cout << jj;
}
cout << endl;
}
}
//uniform(0...n)從一個容器中隨機返回一個數
int uniform(vector<int> v) {
uniform_int_distribution<int> u(0, v.size() - 1);
default_random_engine e(time(0));//不能用秒級的
return v[u(e)];
}
//uniform返回1到x的一個數
static int seeds;
int uniform(int x) {
uniform_int_distribution<int> u(1, x);
default_random_engine e(seeds++);
return u(e);
}
//LV貪心算法,求八皇后問題
void QueensLV()
{
vector<int> col, diag45, diag135;//保存已用的列號、i+j、i-j;
vector<int> tryV;//(i,try[i])表示第i個皇后放置的位置
int searchNode = 0;//搜索節點數
int i = 0;//行號
int j = 0;//列號
int nb =0;
while (i < NUMOFQUEEN) {
vector<int> okCol;//存放這一行中可以使用的列號
nb= 0;//nb的值爲第i個皇后可以放的位置總數
for (int j2 = 0; j2 < NUMOFQUEEN; ++j2) {//查找這一行中能夠用的j
if ((find(col.begin(), col.end(), j2) == col.end()) && (find(diag45.begin(), diag45.end(), i+j2) == diag45.end())&& (find(diag135.begin(), diag135.end(),i-j2) == diag135.end())){
okCol.push_back(j2);
nb++;
}
}
if(okCol.size()>0)
j = uniform(okCol);
if (nb > 0) {//表示這一行可以放置皇后
tryV.push_back(j);
col.push_back(j);
diag135.push_back(i - j);
diag45.push_back(i + j);
++i;
++searchNode;
}
if (nb == 0) {//當前方法沒辦法放置所有皇后,就重置集合,從頭開始重來
diag45.clear();
diag135.clear();
col.clear();
i =j= 0;
tryV.clear();
}
}
//打印
for (auto ii = 0; ii < NUMOFQUEEN; ++ii) {
for (auto jj = 0; jj < NUMOFQUEEN; ++jj)
if (tryV[ii] == jj)
cout << "X";
else
cout << "O";
cout << endl;
}
cout << "搜索節點數:" << searchNode << endl;
}
//
bool backTrace2(int k,vector<int> tryV,set<int> &col,set<int> &diag45,set<int> &diag135,int &searchNode) {
/*vector<int> tryV(1+NUMOFQUEEN);
set<int> col, diag45,diag135;*/
//求k到NUMOFQUEEN皇后怎麼放置,包括第k和第NUMOFQUEEN個皇后.
int j = 1;
while (k <= NUMOFQUEEN) {
bool findJ=false;
for (; j <= NUMOFQUEEN; ++j) {
if (col.find(j) == col.end() && diag45.find(j - k) == diag45.end() && diag135.find(j + k) == diag135.end())
{
findJ = true;
break;
}
}
if (findJ) {
++searchNode;
tryV[k] = j;
col.insert(j);
diag45.insert(j - k);
diag135.insert(j + k);
++k;
j = 1;
}
else {
--k;
j = tryV[k];
if (j == 0)
return false;
tryV[k] = 0;
col.erase(col.find(j));
diag45.erase(diag45.find(j - k));
diag135.erase(diag135.find(j + k));
++j;
}
}
//cout << k << endl;
if (k == 1+NUMOFQUEEN) {
//for (auto ii : tryV)
//cout << ii << " ";
//cout << endl;
return true;
}
else
return false;
}
//第二個隨機算法
bool QueensLV2(int &searchNode,int stepVegas) {
set<int> col, diag45, diag135;//分別是已用的列、45度方向的行列之差、135度方向的行列之和
vector<int> tryV(NUMOFQUEEN+1);//(k,tryV[k})表示第k的皇后放置的位置
int k = 0;//行號
int j = 0;//列號
//毫秒級時間戳,用於生成隨機數
struct timeb tp;
ftime(&tp);
int seeds = tp.time / 1000 + tp.millitm;//隨機數初始種子
while (k < stepVegas) {
int nb = 0;//nb表示當前行可以放置的位置數目
for (int i = 1; i <= NUMOFQUEEN; ++i) {
if (col.find(i)==col.end()&&diag45.find(i-k-1)==diag45.end()&&diag135.find(i+k+1)==diag135.end()) {
++nb;
if (uniform(nb) == 1)//從nb的位置中隨機返回一個
j = i;
}
}
if (nb > 0) {
k++;
tryV[k] = j;//將列號記錄下來
col.insert(j);
diag45.insert(j - k);
diag135.insert(j + k);
++searchNode;//搜索節點增加
}
if (nb == 0)
break;
}
if (k == stepVegas) {
if(backTrace2(k + 1, tryV, col, diag45, diag135,searchNode))
return true;
else return false;
}
else
return false;
}
void printV(vector<int> v){
for (auto i : v)
cout << i << " ";
cout << endl;
}
int main() {
clock_t start, finish;
double totaltime;
start = clock();//開始時鐘
struct timeb tp;
ftime(&tp);
seeds = tp.millitm + tp.time / 1000;
cout << "stepVegas s p\n";
int stepVegas = 0;
for (; stepVegas <= NUMOFQUEEN; ++stepVegas) {
int sum = 0;
int searchNode = 0;
int j = 0;
for (int i = 0; i < 100; ++i) {
while (!QueensLV2(searchNode, stepVegas))++j;
}
sum += searchNode;
cout << stepVegas << " " << sum /100.0<<" "<<j<< endl;
}
/*
for (int i = 0; i < 100; ++i) {
int searchNode = 0;
while (!QueensLV2(searchNode, 20));
cout << searchNode << endl;
}*/
//cout << searchNode << endl;
finish = clock();//結束時鐘
totaltime = (double)(finish - start) ;
cout << "程序運行時間:" << totaltime << "毫秒" << endl;
return 0;
}