N 个皇后区的快速启发式算法 (n > 1000)
fast heuristic algorithm for n queens (n > 1000)
我写了两个程序:
- 将 n 个皇后
- 放在棋盘上,没有任何回溯算法的威胁。 但这对大N来说非常沉重。 最后,您可以运行 100 个皇后。
- 将 n 个皇后放在棋盘上,没有任何爬山算法的威胁。 这个算法比过去的解决方案更好,但 2 个皇后需要 300 分钟,这次呈指数级增长!
但是我不知道要做那么快!我想要算法来更快地做到这一点.
我想要更快的方式来快速解决 1000 个皇后的问题。
这是我的爬山密码:
// N queen - Reset Repair Hill Climbing.cpp
// open-mind.ir
#include "stdafx.h"
#include <vector>
#include <iostream>
#include <fstream>
#include <time.h>
#include <iomanip>
using namespace std;
//print solution in console
void printBoardinTerminal(int *board, int len)
{
for (int i = 0; i < len; i++)
{
for (int j = 0; j < len; j++)
{
if (j == board[i])
{
cout << 1 << " ";
}
else
{
cout << 0 << " ";
}
}
cout << endl;
}
}
//print solution in File
void printBoardinFile(int *board, int len)
{
ofstream fp("output.txt", ios::out);
fp << "Answer for " << len << " queen: n n";
for (int i = 0; i < len; i++)
{
for (int j = 0; j < len; j++)
{
fp << "----";
}
fp << "n|";
for (int j = 0; j < len; j++)
{
if (j == board[i])
{
fp << setw(4) << "* |" ;
}
else
{
fp << setw(4) << " |";
}
}
fp << "n";
}
}
//The number of queens couples who are threatened themself
int evaluate(int *board, int len)
{
int score = 0;
for (int i = 0; i < len - 1; i++)
{
for (int j = i + 1; j < len; j++)
{
if (board[i] == board[j])
{
score++;
continue;
}
if (board[i] - board[j] == i - j)
{
score++;
continue;
}
if (board[i] - board[j] == j - i)
{
score++;
continue;
}
}
}
return score;
}
//generate new state from current state
int* generateBoard(int *board,int len)
{
vector <int> choice;
int temp;
int score;
int eval = evaluate(board, len);
int k;
int *boardOut;
boardOut = new int [len];
for (int i = 0; i < len; i++)
{
boardOut[i] = board[i];
}
for (int i = 0; i < len; i++)
{
choice.clear();
choice.push_back(boardOut[i]);
temp = boardOut[i];
for (int j = 0; j < len; j++)
{
boardOut[i] = j;
k = evaluate(boardOut, len);
if (k == eval)
{
choice.push_back(j);
}
if (k < eval)
{
choice.clear();
choice.push_back(j);
eval = k;
}
}
boardOut[i] = choice[rand() % choice.size()];
}
return boardOut;
}
//in this function , genarate new state by pervious function and if it has better value then replaces that by current state
bool findNextState(int *board, int len)
{
int maineval = evaluate(board, len);
int *tempBoard;
tempBoard = generateBoard(board, len);
if (evaluate(tempBoard, len) < maineval)
{
for (int p = 0; p < len; p++)
{
board[p] = tempBoard[p];
}
return true;
}
return false;
}
// make random initial state , put one queen in each row
void initialRandomBoard(int * board, int len)
{
bool access;
int col;
for (int i = 0; i < len; i++)
{
board[i] = rand() % len;
}
}
//this function include a loop that call findNextState function , and do that until reach solution
//if findNextState function return NULL then we reset current state
void SolveNQueen(int len)
{
cout << "The program is under process! wait!" << endl;
int *board;
board = new int[len];
initialRandomBoard(board, len);
while (evaluate(board, len) != 0)
{
if (!findNextState(board, len))
{
initialRandomBoard(board, len);
}
}
//
cout << endl << "Anwser for " << len << " queens: "<< endl << endl;
printBoardinTerminal(board, len);
printBoardinFile(board, len);
//
}
int main()
{
int n;
srand(time(NULL));
cout << "Enter number 'N', 'N' indicate numbers of queens in "N * N" chess board: " << endl;
cin >> n;
if (n < 4)
{
cout << "'n' must be uper than 3!" << endl;
exit(1);
}
SolveNQueen(n);
cout << endl << "As well , you can see result in "output.txt"." << endl << endl;
return 0;
}
注意:此答案假设您有兴趣找到一个有效的解决方案。如果您需要找到所有解决方案,这将对您无济于事。
Russell&Norvig的《人工智能:现代方法,第二版》第5章:约束满足问题第143页有一个表格,比较了各种任务的各种约束满足问题算法。(最新版本是第三版,现在看来约束满足问题已经是第6章了。
根据他们的结果,最小冲突本地搜索启发式在n-Queens问题测试的算法中得分最高,平均需要4K检查,而回溯和前向检查需要>40,000K检查。
算法非常简单:
- 选择皇后区的初始(随机或预选)分配
- 虽然有受到威胁的女王(或者直到你厌倦了尝试......值得将其放在
for
循环中以限制尝试次数):- 随机选择一个受威胁的女王
- 将选定的女王移动到正方形以最大程度地减少冲突
在最后一步中,我假设每个女王都受限于她的列,因此她只能更改列内的行。如果有几行可以最大限度地减少当前女王的冲突,则可以在其中随机选择。
就是这样。它是完全随机的,而且效果很好。
编辑:
我在这里有一个注释,不记得当我实现这个算法时我得到了多高,说我知道我已经得到了 100 多个。我没有找到我的旧代码,但我还是决定把一些东西放在一起。事实证明,这种方法比我记忆中的要有效得多。以下是 10 位皇后的结果:
Starting Configuration:
14 0 2 13 12 17 10 14 14 2 9 8 11 10 6 16 0 7 10 8
Solution found
Ending Configuration:
17 2 6 12 19 5 0 14 16 7 9 3 1 15 11 18 4 13 8 10
Elapsed time (sec): 0.00167
Number of moves: 227
在没有尝试优化代码的情况下,以下是我针对不同问题大小得到的大致时间:
Queens ~Time(sec)
====== ==========
100 0.03
200 0.12
500 1.42
1000 9.76
2000 72.32
5000 1062.39
我只为5000个皇后运行了最后一个,但是在18分钟内找到解决方案比我预期的要快。
相关文章:
- EASTL矢量<向量<int>>连续的
- 如何在C++中写入 1000 个文件时有效地缓冲
- 为什么 Lisp 中 1000 阶乘的计算如此之快(并显示正确的结果)?
- 为什么 std::find( s.begin(), s.end(), val ) 比集合 s 的 s.find(val) 慢 1000 倍<int>?
- 为什么可以将 std::unique_ptr* u1 <A>作为 u1[1000] 访问并且它仍然有效
- C++:创建1000次唯一的随机分布,在任何分布中都没有重复的数字
- int x=1000和just x=1000产生不同的值
- C++2骰子滚动1000万次开始
- 电脑从1-1000猜你的号码(必须在10次尝试中)
- 掷2个骰子1000次
- 如何计算大小为 1000 x 1000 的 2D 数组中 2 个元素之间的步幅?C++
- 如何在没有同步的情况下使用多个线程(2、4,8、16 个线程)在循环(10,100、1000 个周期)中打印字符串?
- 同一程序的运行时间差异很大,有时达到1000+us
- 为什么 CSpinButtonCtrl 不能正确处理大于 1000 的数字?
- 将"float*"赋值为"float* [1000]"中的不兼容类型
- C - 创建矢量&lt; vector&lt; double&gt;&gt;矩阵具有分配而不是inizializ
- C 程序仅在字符阵列获得“ 1000!”的输入时才在DELETE上崩溃
- C 字符串比较“祝您好运”&gt;“再见”
- GCC 和 LLVM 中的正则表达式速度相差 1000 倍
- 为什么将此对向量&lt; map&lt; int,int&gt;&gt;中的地图进行更新.失败