对经典算法的问题的回顾与感想

对八皇后问题和八数码问题分别用最陡上升爬山法、首选爬山法、随机重启爬山法、模拟退火算法来实现,并且分析他们的性能。


分析

要求实现的各个算法是有共同点的,比如,八皇后问题相关算法拥有相同的状态空间,每个算法都有从当前状态获取下一状态的需求,各个算法细节不同,共同点是,它们都是算法。
基于这样的想法,我们可以将代码划分为3层:


运行示例

代码比较长,附在最后面,读者基于上述的思路是不难看懂的。
我们默认读者已经知道这几个算法的思路,代码直接给出实现。如果不懂,请翻阅人工智能课本,里面有讲。

图1,八数码问题的交互界面

图2,八皇后问题的交互界面

图3 输出界面示例


结果分析

为了便于研究,我们首先定义三个指标,分别是:
①因变1:算法找到解的成功率;
②因变2:算法找到的解的平均路径长度
③因变3:算法找到解的平均耗散,用搜索的结点数衡量

对八皇后的结果分析


观察表1,我们可以发现如下对八皇后问题的有趣结论:
(1)在八皇后问题中,当随机测例数增加,最陡上升爬山法和首选爬山法的成功率都收敛到0.142左右,与书本结论吻合。
(2)最陡上升爬山法的解的平均路径长度收敛到0.58左右,而首选爬山是0.83左右。这说明最陡爬山法的平均走了更短的路径到达全局最优解。
(3)虽然最陡上山法的平均路径长度更短,但是搜索耗散却比首选爬山法多,原因是,为了得到最陡的子结点,需要探查所有的相邻子节点。反应在数据上是,最陡上山法的解的平均耗散率收敛到32左右,而首选爬山法仅为19左右。
(4)随机重启爬山法比最陡上升法和首选爬山法的成功率兜大大提高,重启次数为5,随机测例10000时,成功率高达0.6,约为前二者算法的4倍。但是也付出了更大的代价,平均解长度是最陡上升法的18.4倍,是首选爬山法的12.7倍;解的平均耗散度是最陡爬山法的17倍,是首选爬山法的28.4倍。
(5)随机重启爬山法的成功率随初始温度的增加而上升。当重启次数为0时,退化为首选爬山法,成功率、解长度、解耗散度都和首选爬山法接近。随着重启次数增加,成功率也大大上升,当重启次数为7时,成功率为0.7092,是重启次数为0的4.96倍,相应地,解长度和解耗散也大大增加。
(6)模拟退火算法随起始温度上升,成功率也上升。理论上分析,当起始温度足够高,退火过程足够长的时候,成功率可以接近1。但是其开销也会变得极大,0.43成功率的退火算法的解长度是0.46成功率退火算法的3706倍,而解耗散是146.5倍。

对八数码问题的结果分析


观察表2,我们可以发现如下对八数码问题的有趣结论:
(1)与八皇后问题类似,最陡上升和首选爬山法收敛到了接近的成功率,此处是0.4左右。但是解长度和解耗散并没有八皇后问题大,可能的原因是,八数码问题的相邻子结点空间远比八皇后问题大。
(2)这里没有使用随机重启算法,因为八数码问题关心解路径,如果使用了随机重启算法,则违反了规则。
(3)初始状态是通过目标随机打乱得来的,先随机取上限次数一下的打乱数x,然后随机方向移动白块x次。我们发现,打乱步数上限的多少,对成功率的影响并不大,无论最陡爬山算法,首选爬山算法,模拟退火算法都如此。可能的原因是,在打乱次数上限很小的时候,成功率就已经收敛了。
(4)模拟退火算法在八数码问题和八皇后问题的表现类似。都随着初始温度的上升而上升,同时解长度和解耗散急剧增大。理论上,当初始温度足够高,成功率会逼近1。

代码

由于实在太多,我就不逐行解释。读者把握分析时的思路,应该不难读懂。

//*****************************************************
// eightQueue.hpp
// 包括八皇后问题的eightQueueNode类和eightQueueNodeFactory的实现
//*****************************************************
#include <iostream>
#include <stdlib.h>
#include <time.h> class eightQueueNode {
public:int arr[8];eightQueueNode(int a,int b, int c, int d, int e, int f, int g, int h){arr[0] = a;arr[1] = b;arr[2] = c;arr[3] = d;arr[4] = e;arr[5] = f;arr[6] = g;arr[7] = h;}eightQueueNode(const eightQueueNode& node) {arr[0] = node.arr[0];arr[1] = node.arr[1];arr[2] = node.arr[2];arr[3] = node.arr[3];arr[4] = node.arr[4];arr[5] = node.arr[5];arr[6] = node.arr[6];arr[7] = node.arr[7];}~eightQueueNode(){}bool operator==(const eightQueueNode& node) {return (this->arr[0] == node.arr[0]) && (this->arr[1] == node.arr[1]) && (this->arr[2] == node.arr[2])&& (this->arr[3] == node.arr[3]) && (this->arr[4] == node.arr[4]) && (this->arr[5] == node.arr[5])&& (this->arr[6] == node.arr[6]) && (this->arr[7] == node.arr[7]);}
};class eightQueueNodeFactory{private:int ranNum(){return rand() % 8;}bool isTheArrayAllTrue(bool isAllCheck[64]) {for(int i = 0; i < 64; i++) {if(isAllCheck[i] == false) {return false;}}return true;}public:eightQueueNodeFactory(){srand((unsigned)time(NULL));}eightQueueNode getARandomNode() {return eightQueueNode(ranNum(),ranNum(),ranNum(),ranNum(),ranNum(),ranNum(),ranNum(),ranNum());}int evaluate(const eightQueueNode& node) {int numOfAttack = 0;for(int i = 0; i < 7; i++) {for(int j = i + 1; j < 8; j++) {if (node.arr[i] == node.arr[j] || (node.arr[i]-node.arr[j]) == (i-j) || (node.arr[i]-node.arr[j]) == (j-i)) {numOfAttack++;}}}return numOfAttack;}int getBestNextNode(eightQueueNode& node) {eightQueueNode ans = node;eightQueueNode tmp = node;int costOfSearch = 0;for(int i = 0; i < 64; i++) {tmp = node;tmp.arr[i/8] = i % 8;if(evaluate(tmp) < evaluate(ans)) {ans = tmp;} else if(evaluate(tmp) == evaluate(ans)) {if(rand() / double(RAND_MAX) > 0.5) {ans = tmp;}}}node = ans;return 56;}// the input node is confirmed to be not the bestint getNextBetterNode(eightQueueNode& node) {bool isAllCheck[64];for(int i = 0; i < 64; i++) isAllCheck[i] = false;eightQueueNode tmp = node;int costOfSearch = 1;while(evaluate(tmp) >= evaluate(node)) {// 子节点全部搜索过,都比当前差if(isTheArrayAllTrue(isAllCheck)) return costOfSearch;// 初始化,找下一邻居tmp = node;int a = rand() % 64;isAllCheck[a] = true;tmp.arr[a/8] = a % 8;costOfSearch++;if(tmp == node) {continue;}}node = tmp;return costOfSearch;}int getARandomNeighbour(eightQueueNode& node) {eightQueueNode tmp = node;int cost = 0;while(node == tmp) {cost++;int a = rand() % 64;tmp.arr[a/8] = a % 8;}node = tmp;return cost;}
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
//***************************************
// eightQueueRunner.cpp
// 包括八皇后问题的各个算法和简单交互界面实现
//***************************************
#include "eightQueue.hpp"
#include <iostream>
#include <math.h>using namespace std;
eightQueueNodeFactory factory;#define NUM_OF_LOOP 10000
#define NUM_OF_REBOOT 0
#define BEGIN_TEMP 10000
#define STOP_TEMP 1void mostSteepClimbing();
void firstSeclectionClimbing();
void randomRebootClimbing();
void simulatedAnnealing();int main() {int choice = 0;do{cout << endl;cout << "The Eight Queue Problem:" << endl;cout << "   0 -- most steep climbing" << endl;cout << "   1 -- first selection climbing" << endl;cout << "   2 -- random reboot climbing" << endl;cout << "   3 -- stimulated annealing" << endl;cout << "please input your choice: ";cin >> choice;if (choice == -1) break;switch(choice) {case 0:mostSteepClimbing();break;case 1:firstSeclectionClimbing();break;case 2:randomRebootClimbing();break;case 3:simulatedAnnealing();break;default:break;}}while(true);return 0;
}void mostSteepClimbing() {int sumOfsuccess = 0, sumOfFailure = 0;double theSumOfCostOfSearchOfSuccess = 0, theSumLengthOfSolutionOfSuccess = 0;for(int i = 0; i < NUM_OF_LOOP; i++) {bool success = false;int cost = 0, lenOfRoute = 0;eightQueueNode curState = factory.getARandomNode();eightQueueNode tmp = curState;while(true) {// if satisfied, then breakif (factory.evaluate(curState) == 0) {success = true;break;}lenOfRoute++;cost += factory.getBestNextNode(tmp);if(factory.evaluate(tmp) >= factory.evaluate(curState)) {break;} else {curState = tmp;}}if(success) {sumOfsuccess++;theSumOfCostOfSearchOfSuccess += cost;theSumLengthOfSolutionOfSuccess += lenOfRoute;} else {sumOfFailure++;}// outputcout << "case " << i << "  cost: " << cost << " " << "lengthOfSolution: " << lenOfRoute << " ";if(success){cout << "success ";} else {cout << "failure ";}cout << endl;}cout << "Sum of success: " << sumOfsuccess << endl;cout << "Sum of failure " << sumOfFailure << endl;cout << "Rate of success " << sumOfsuccess/((double)(sumOfFailure + sumOfsuccess)) << endl;  cout << "The average solution length of success:" << theSumLengthOfSolutionOfSuccess/NUM_OF_LOOP << endl;cout << "The average cost of search of success:" << theSumOfCostOfSearchOfSuccess/NUM_OF_LOOP << endl;  return;
}void firstSeclectionClimbing() {int sumOfsuccess = 0, sumOfFailure = 0;double theSumOfCostOfSearchOfSuccess = 0, theSumLengthOfSolutionOfSuccess = 0;for(int i = 0; i < NUM_OF_LOOP; i++) {bool success = false;int cost = 0, lenOfRoute = 0;eightQueueNode curState = factory.getARandomNode();eightQueueNode tmp = curState;while(true) {// if satisfied, then breakif (factory.evaluate(curState) == 0) {success = true;break;}lenOfRoute++;cost += factory.getNextBetterNode(tmp);if(factory.evaluate(tmp) >= factory.evaluate(curState)) {break;} else {curState = tmp;}}if(success) {sumOfsuccess++;theSumOfCostOfSearchOfSuccess += cost;theSumLengthOfSolutionOfSuccess += lenOfRoute;} else {sumOfFailure++;}// outputcout << "case " << i << "  cost: " << cost << " " << "lengthOfSolution: " << lenOfRoute << " ";if(success){cout << "success ";} else {cout << "failure ";}cout << endl;}cout << "Sum of success: " << sumOfsuccess << endl;cout << "Sum of failure " << sumOfFailure << endl;cout << "Rate of success " << sumOfsuccess/((double)(sumOfFailure + sumOfsuccess)) << endl;  cout << "The average solution length of success:" << theSumLengthOfSolutionOfSuccess/NUM_OF_LOOP << endl;cout << "The average cost of search of success:" << theSumOfCostOfSearchOfSuccess/NUM_OF_LOOP << endl;  return;
}void randomRebootClimbing() {int sumOfsuccess = 0, sumOfFailure = 0;double theSumOfCostOfSearchOfSuccess = 0, theSumLengthOfSolutionOfSuccess = 0;for(int i = 0; i < NUM_OF_LOOP; i++) {bool success = false;int cost = 0, lenOfRoute = 0, numOfReboot = NUM_OF_REBOOT;eightQueueNode curState = factory.getARandomNode();eightQueueNode tmp = curState;while(true) {// if satisfied, then breakif (factory.evaluate(curState) == 0) {success = true;break;}lenOfRoute++;cost += factory.getNextBetterNode(tmp);if(factory.evaluate(tmp) >= factory.evaluate(curState)) {if(numOfReboot > 0) {numOfReboot--;curState = factory.getARandomNode();tmp = curState;} else {break;}} else {curState = tmp;}}if(success) {sumOfsuccess++;theSumOfCostOfSearchOfSuccess += cost;theSumLengthOfSolutionOfSuccess += lenOfRoute;} else {sumOfFailure++;}// outputcout << "case " << i << "  cost: " << cost << " " << "lengthOfSolution: " << lenOfRoute << " ";if(success){cout << "success ";} else {cout << "failure ";}cout << endl;}cout << "Sum of success: " << sumOfsuccess << endl;cout << "Sum of failure " << sumOfFailure << endl;cout << "Rate of success " << sumOfsuccess/((double)(sumOfFailure + sumOfsuccess)) << endl;  cout << "The average solution length of success:" << theSumLengthOfSolutionOfSuccess/NUM_OF_LOOP << endl;cout << "The average cost of search of success:" << theSumOfCostOfSearchOfSuccess/NUM_OF_LOOP << endl;  return;
}void simulatedAnnealing() {int sumOfsuccess = 0, sumOfFailure = 0;double theSumOfCostOfSearchOfSuccess = 0, theSumLengthOfSolutionOfSuccess = 0;for(int i = 0; i < NUM_OF_LOOP; i++) {bool success = false;int cost = 0, lenOfRoute = 0;double curTemp = BEGIN_TEMP;eightQueueNode curState = factory.getARandomNode();eightQueueNode tmp = curState;while(true) {// if satisfied, then breakif (factory.evaluate(curState) == 0) {success = true;break;} else if(curTemp < STOP_TEMP){// 温度过低,则停止break;}// 走一步,则温度下降lenOfRoute++;curTemp -= 1;cost += factory.getARandomNeighbour(tmp);int deltaOfEvalutaion = factory.evaluate(tmp) - factory.evaluate(curState);if(deltaOfEvalutaion >= 0) {// 根据温度差来决定是否接受double probility = exp(curTemp/(deltaOfEvalutaion));if(rand() / double(RAND_MAX) < deltaOfEvalutaion) {curState = tmp;}} else {curState = tmp;}}if(success) {sumOfsuccess++;theSumOfCostOfSearchOfSuccess += cost;theSumLengthOfSolutionOfSuccess += lenOfRoute;} else {sumOfFailure++;}// outputcout << "case " << i << "  cost: " << cost << " " << "lengthOfSolution: " << lenOfRoute << " ";if(success){cout << "success ";} else {cout << "failure ";}cout << endl;}cout << "Sum of success: " << sumOfsuccess << endl;cout << "Sum of failure " << sumOfFailure << endl;cout << "Rate of success " << sumOfsuccess/((double)(sumOfFailure + sumOfsuccess)) << endl;  cout << "The average solution length of success:" << theSumLengthOfSolutionOfSuccess/NUM_OF_LOOP << endl;cout << "The average cost of search of success:" << theSumOfCostOfSearchOfSuccess/NUM_OF_LOOP << endl;  return;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
//***************************************************************
// eightDigit.hpp
// 包括八数码问题的eightDigitNode类和eightDigitFactory类的实现
// **************************************************************
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <math.h>#define LOOP_OF_SHUFFLE 50class eightDigitNode {
public:int arr[9];int blank_x = 2, blank_y = 2;eightDigitNode(){for(int i = 0; i < 8; i++) {arr[i] = i+1;}arr[8] = 0;}~eightDigitNode(){}eightDigitNode(const eightDigitNode& node) {arr[0] = node.arr[0];arr[1] = node.arr[1];arr[2] = node.arr[2];arr[3] = node.arr[3];arr[4] = node.arr[4];arr[5] = node.arr[5];arr[6] = node.arr[6];arr[7] = node.arr[7];arr[8] = node.arr[8];blank_x = node.blank_x;blank_y = node.blank_y;}bool operator==(const eightDigitNode& node) {for(int i = 0; i < 8; i++) {if(arr[i] != node.arr[i]) return false;}return true;}bool goLeft() {if(blank_y == 0) {return false;} else {arr[blank_x*3+blank_y] = arr[blank_x*3+blank_y-1];arr[blank_x*3+blank_y-1] = 0;blank_y--;return true;}}bool goRight() {if(blank_y == 2) {return false;} else {arr[blank_x*3+blank_y] = arr[blank_x*3+blank_y+1];arr[blank_x*3+blank_y+1] = 0;blank_y++;return true;}}bool goUp() {if(blank_x == 0) {return false;} else {arr[blank_x*3+blank_y] = arr[(blank_x-1)*3+blank_y];arr[(blank_x-1)*3+blank_y] = 0;blank_x--;return true;}}bool goDown() {if(blank_x == 2) {return false;} else {arr[blank_x*3+blank_y] = arr[(blank_x+1)*3+blank_y];arr[(blank_x+1)*3+blank_y] = 0;blank_x++;  return true;}}
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
class eightDigitNodeFactory{
private:int getManhattanDistian(const int& src, const int& target) {return abs(src%3 - target%3) + abs(src/3 - target/3); }int getNumOfWrongNumber(const eightDigitNode& node) {int res = 0;for(int i = 0; i < 8; i++) {if (node.arr[i] != i+1) res++;}if(node.arr[8] != 0) res++;return res; }bool getANeighbourNode(int direction, eightDigitNode& node) {switch(direction) {case 0: return node.goLeft();case 1: return node.goUp();case 2: return node.goRight();default:return node.goDown();}}bool isTheArrayAllTrue(bool isAllCheck[4]) {for(int i = 0; i < 4; i++) {if(isAllCheck[i] == false) {return false;}}return true;}public:eightDigitNodeFactory() {srand((unsigned)time(NULL));}eightDigitNode getARandomNode() {eightDigitNode output;int timesOfShuffle = rand() % LOOP_OF_SHUFFLE;while(timesOfShuffle--) {while(!getANeighbourNode(rand()%4, output));}return output;}int evaluate(const eightDigitNode& node) {eightDigitNode tmp;int distanceToTargetState = 0;for(int i = 0; i < 9; i++) {int j = 0;while(tmp.arr[j] != node.arr[i]) {j++;}distanceToTargetState += getManhattanDistian(i, j);}return distanceToTargetState + 3*getNumOfWrongNumber(node);}int getBestNextNode(eightDigitNode& node) {eightDigitNode tmp = node, ans = node;for(int i = 0; i < 4; i++) {tmp = node;if(getANeighbourNode(i, tmp) && evaluate(tmp) < evaluate(ans)) {ans = tmp;} else if(evaluate(tmp) == evaluate(ans)) {if(rand() / double(RAND_MAX) > 0.5) {ans = tmp;}}}node = ans;return 4;}int getNextBetterNode(eightDigitNode& node) {bool isAllCheck[4];for(int i = 0; i < 4; i++) {isAllCheck[i] = false;}eightDigitNode tmp = node;int costOfSearch = 1;while(evaluate(tmp) >= evaluate(node)) {// 子节点全部搜索过,都比当前差if(isTheArrayAllTrue(isAllCheck)) return costOfSearch;// 初始化,找下一邻居tmp = node;int a = rand() % 4;isAllCheck[a] = true;getANeighbourNode(a, tmp);costOfSearch++;if(tmp == node) {continue;}}node = tmp;return costOfSearch;}int getARandomNeighbour(eightDigitNode& node) {int costOfSearch = 0;eightDigitNode tmp = node;while(!getANeighbourNode(rand()%4, tmp)) {costOfSearch++;tmp = node;}node = tmp;return costOfSearch;}
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
//*********************************************
// eightDigitRunner.cpp
// 包括八数码问题各算法的和简单交互界面实现
//********************************************
#include "eightDigit.hpp"
#include <iostream>
#include <math.h>using namespace std;
eightDigitNodeFactory factory;#define NUM_OF_LOOP 10000
#define NUM_OF_REBOOT 7
#define BEGIN_TEMP 100000
#define STOP_TEMP 1void mostSteepClimbing();
void firstSeclectionClimbing();
void randomRebootClimbing();
void simulatedAnnealing();int main() {int choice = 0;do{cout << endl;cout << "The Eight Digit Problem:" << endl;cout << "   0 -- most steep climbing" << endl;cout << "   1 -- first selection climbing" << endl;cout << "   2 -- random reboot climbing" << endl;cout << "   3 -- stimulated annealing" << endl;cout << "please input your choice: ";cin >> choice;if (choice == -1) break;switch(choice) {case 0:mostSteepClimbing();break;case 1:firstSeclectionClimbing();break;case 2:randomRebootClimbing();break;case 3:simulatedAnnealing();break;default:break;}}while(true);return 0;
}void mostSteepClimbing() {int sumOfsuccess = 0, sumOfFailure = 0;double theSumOfCostOfSearchOfSuccess = 0, theSumLengthOfSolutionOfSuccess = 0;for(int i = 0; i < NUM_OF_LOOP; i++) {bool success = false;int cost = 0, lenOfRoute = 0;eightDigitNode curState = factory.getARandomNode();eightDigitNode tmp = curState;while(true) {// if satisfied, then breakif (factory.evaluate(curState) == 0) {success = true;break;}lenOfRoute++;cost += factory.getBestNextNode(tmp);if(factory.evaluate(tmp) >= factory.evaluate(curState)) {break;} else {curState = tmp;}}if(success) {sumOfsuccess++;theSumOfCostOfSearchOfSuccess += cost;theSumLengthOfSolutionOfSuccess += lenOfRoute;} else {sumOfFailure++;}// outputcout << "case " << i << "  cost: " << cost << " " << "lengthOfSolution: " << lenOfRoute << " ";if(success){cout << "success ";} else {cout << "failure ";}cout << endl;}cout << "Sum of success: " << sumOfsuccess << endl;cout << "Sum of failure " << sumOfFailure << endl;cout << "Rate of success " << sumOfsuccess/((double)(sumOfFailure + sumOfsuccess)) << endl;cout << "The average solution length of success:" << theSumLengthOfSolutionOfSuccess/NUM_OF_LOOP << endl;cout << "The average cost of search of success:" << theSumOfCostOfSearchOfSuccess/NUM_OF_LOOP << endl;  return;
}void firstSeclectionClimbing() {int sumOfsuccess = 0, sumOfFailure = 0;double theSumOfCostOfSearchOfSuccess = 0, theSumLengthOfSolutionOfSuccess = 0;for(int i = 0; i < NUM_OF_LOOP; i++) {bool success = false;int cost = 0, lenOfRoute = 0;eightDigitNode curState = factory.getARandomNode();eightDigitNode tmp = curState;while(true) {// if satisfied, then breakif (factory.evaluate(curState) == 0) {success = true;break;}lenOfRoute++;cost += factory.getNextBetterNode(tmp);if(factory.evaluate(tmp) >= factory.evaluate(curState)) {break;} else {curState = tmp;}}if(success) {sumOfsuccess++;theSumOfCostOfSearchOfSuccess += cost;theSumLengthOfSolutionOfSuccess += lenOfRoute;} else {sumOfFailure++;}// outputcout << "case " << i << "  cost: " << cost << " " << "lengthOfSolution: " << lenOfRoute << " ";if(success){cout << "success ";} else {cout << "failure ";}cout << endl;}cout << "Sum of success: " << sumOfsuccess << endl;cout << "Sum of failure " << sumOfFailure << endl;cout << "Rate of success " << sumOfsuccess/((double)(sumOfFailure + sumOfsuccess)) << endl;  cout << "The average solution length of success:" << theSumLengthOfSolutionOfSuccess/NUM_OF_LOOP << endl;cout << "The average cost of search of success:" << theSumOfCostOfSearchOfSuccess/NUM_OF_LOOP << endl;  return;
}
void randomRebootClimbing() {int sumOfsuccess = 0, sumOfFailure = 0;double theSumOfCostOfSearchOfSuccess = 0, theSumLengthOfSolutionOfSuccess = 0;for(int i = 0; i < NUM_OF_LOOP; i++) {bool success = false;int cost = 0, lenOfRoute = 0;eightDigitNode curState = factory.getARandomNode();eightDigitNode tmp = curState;while(true) {// if satisfied, then breakif (factory.evaluate(curState) == 0) {success = true;break;}lenOfRoute++;cost += factory.getNextBetterNode(tmp);if(factory.evaluate(tmp) >= factory.evaluate(curState)) {break;} else {curState = tmp;}}if(success) {sumOfsuccess++;theSumOfCostOfSearchOfSuccess += cost;theSumLengthOfSolutionOfSuccess += lenOfRoute;} else {sumOfFailure++;}// outputcout << "case " << i << "  cost: " << cost << " " << "lengthOfSolution: " << lenOfRoute << " ";if(success){cout << "success ";} else {cout << "failure ";}cout << endl;}cout << "Sum of success: " << sumOfsuccess << endl;cout << "Sum of failure " << sumOfFailure << endl;cout << "Rate of success " << sumOfsuccess/((double)(sumOfFailure + sumOfsuccess)) << endl;  cout << "The average solution length of success:" << theSumLengthOfSolutionOfSuccess/NUM_OF_LOOP << endl;cout << "The average cost of search of success:" << theSumOfCostOfSearchOfSuccess/NUM_OF_LOOP << endl;  return;
}
void simulatedAnnealing() {int sumOfsuccess = 0, sumOfFailure = 0;double theSumOfCostOfSearchOfSuccess = 0, theSumLengthOfSolutionOfSuccess = 0;for(int i = 0; i < NUM_OF_LOOP; i++) {bool success = false;int cost = 0, lenOfRoute = 0;double curTemp = BEGIN_TEMP;eightDigitNode curState = factory.getARandomNode();eightDigitNode tmp = curState;while(true) {// if satisfied, then breakif (factory.evaluate(curState) == 0) {success = true;break;} else if(curTemp < STOP_TEMP){// 温度过低,则停止break;}// 走一步,则温度下降lenOfRoute++;curTemp -= 1;cost += factory.getARandomNeighbour(tmp);int deltaOfEvalutaion = factory.evaluate(tmp) - factory.evaluate(curState);if(deltaOfEvalutaion >= 0) {// 根据温度差来决定是否接受double probility = exp(curTemp/(deltaOfEvalutaion));if(rand() / double(RAND_MAX) < deltaOfEvalutaion) {curState = tmp;}} else {curState = tmp;}}if(success) {sumOfsuccess++;theSumOfCostOfSearchOfSuccess += cost;theSumLengthOfSolutionOfSuccess += lenOfRoute;} else {sumOfFailure++;}// outputcout << "case " << i << "  cost: " << cost << " " << "lengthOfSolution: " << lenOfRoute << " ";if(success){cout << "success ";} else {cout << "failure ";}cout << endl;}cout << "Sum of success: " << sumOfsuccess << endl;cout << "Sum of failure " << sumOfFailure << endl;cout << "Rate of success " << sumOfsuccess/((double)(sumOfFailure + sumOfsuccess)) << endl;  cout << "The average solution length of success:" << theSumLengthOfSolutionOfSuccess/NUM_OF_LOOP << endl;cout << "The average cost of search of success:" << theSumOfCostOfSearchOfSuccess/NUM_OF_LOOP << endl;  return;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
                 <link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-258a4616f7.css" rel="stylesheet"></div>

八皇后问题和八数码问题的最陡上升爬山法、首选爬山法、随机重启爬山法、模拟退火算法的分析和实现相关推荐

  1. 爬山法、随机重启爬山法、模拟退火算法对八皇后问题和八数码问题的性能测试...

    代码地址:https://github.com/laiy/AI/tree/master/awesome-search 一些前提: 1. 首先要明确这些算法并不是用于解决传统的搜索问题的(环境是可观察的 ...

  2. Python:爬山法/随机重启爬山法/允许侧移的爬山法解决八皇后问题

    文章目录 1 八皇后问题 2 程序代码 2.1 程序1 2.2 程序2 2.3 程序3 2.3.1 爬山法 2.3.2 随机重启爬山法 2.3.3 允许皇后侧移的爬山法 3 评价 1 八皇后问题 有一 ...

  3. 八皇后java_经典八皇后问题:Java语言

    问题描述:将八个皇后放在棋盘上,任何两个皇后都不能互相攻击(即没有任何两个皇后在同一行.同一列或者同一对角线上)如图所示,题目来自于<java语言程序设计:基础篇>练习题6.20和6.22 ...

  4. 八皇后问题python_python八皇后问题的解决方法

    本文为大家分享了python八皇后问题的解决方法,供大家参考,具体内容如下 题目: 给定一个 N*N 正方形棋盘,在上面放置 N个棋子,又叫皇后,使每两个棋子都不在同一条横线上.竖线上.斜线上.一般我 ...

  5. 八皇后问题java_八皇后问题java实现

    八皇后问题java实现public class eightqueen { public static int count=0; public static void main(String[] arg ...

  6. JAVA用爬山法解决八皇后问题_八皇后问题爬山法实现(C语言)

    1 #include 2 #include 3 #include 4 #include 5 // 6 //编程题7 //爬山法(八皇后问题)8 // 9 10 11 //棋子结构体12 //typed ...

  7. 1213:八皇后问题1700:八皇后问题

    1213:八皇后问题 时间限制: 1000 ms         内存限制: 65536 KB 提交数: 26315     通过数: 9614 [题目描述] 在国际象棋棋盘上放置八个皇后,要求每两个 ...

  8. 八皇后问题python_python八皇后问题

    两种方法 第二种方法解释 第一层for表示第一个皇后的位置,然后第二层for表示,循环8次,表示其他皇后的位置,最后限制次数,是if判断 def conflict(state,nextx): '定义冲 ...

  9. 八皇后问题python_八皇后问题Python实现

    八皇后问题描述 问题: 国际象棋棋盘是8 * 8的方格,每个方格里放一个棋子.皇后这种棋子可以攻击同一行或者同一列或者斜线(左上左下右上右下四个方向)上的棋子.在一个棋盘上如果要放八个皇后,使得她们互 ...

最新文章

  1. 在线答题系统开发经验mysql,php
  2. hdu 4501 多维0-1背包
  3. 查看selenium python的api小记录
  4. Mac 运行 psql postgres 报错
  5. LINUX用iptable完成端口映射
  6. iMazing for mac中文版苹果iOS设备管理器(已更新至v2.9.12版本)
  7. 机械臂拉格朗日法逆动力学建模仿真(附MATLAB代码)
  8. Hive教程(一) Hive入门教程
  9. oracle按顺序新增字段,Oracle 修改字段顺序的两种方法
  10. PCIe ECAM机制访问PCIE的配置空间
  11. HTTP协议:三.HTTP 报文信息
  12. 推荐几款高性价比电机驱动芯片
  13. Kotlin之Set和Get
  14. Linux桌面录屏分享
  15. buildroot 使用
  16. 【基于参数估计的ISAR定标MATLAB仿真实验】
  17. 新《电商法》下,时下趋势的社交电商社群电商团购合规运营方案已上线成功!...
  18. eCharts给图标添加边框
  19. MAC M1芯片可下载的安卓模拟器Android Emulator
  20. php职教云答案,职教云网课答案公众号

热门文章

  1. 左右xcode的重构选项的一些理解
  2. java.util.Date和java.sql.Date 一点区别
  3. 关于java.util.ConcurrentModificationException和remove倒数第二个元素
  4. 索引(转载自百度百科)
  5. mac地址漂移flapping的前因后果
  6. ProFTPD 初探
  7. 开源 免费 java CMS - FreeCMS2.1 菜单管理
  8. adb shell——Android虚拟机调试必须知道的命令
  9. resize属性,使textarea在ff(火狐)中禁止拉伸
  10. 让UpdatePanel支持文件上传(4):数据传输与解析机制