您的位置:首页 > 大数据 > 人工智能

人工智能-八皇后爬山法(最陡上升,首项选择),随即重新启动法

2015-11-10 18:07 483 查看
#include<iostream>
#include<string>
#include<time h="">
#include<iomanip>
using namespace std;

int qi[64];
int maze[64];

int check(int idx) {
	int index = idx;
	int row = index / 8;
	int col = index % 8;
	int j;
	int h = 0;
	int i;
	for (i = col; i < 64; i += 8)
		if (qi[i] == 1)
			h++;
	for (i = row, j = col; i >= 0 && j >= 0; i--, j--)
		if (qi[i * 8 + j] == 1)
			h++;
	for (i = row, j = col; i < 8 && j < 8; i++, j++)
		if (qi[i * 8 + j] == 1)
			h++;
	for (i = row, j = col; i >= 0 && j < 8; i--, j++)
		if (qi[i * 8 + j] == 1)
			h++;
	for (i = row, j = col; j >= 0 && i < 8; i++, j--)
		if (qi[i * 8 + j] == 1)
			h++;
	return h;
}

bool hill_climbing(int n) {
	int i;
	int max;
	int ff;
	int step = 0;
	do {
		for (int i = 0; i < 64; i++) {
			qi[i] = maze[i];
		}

		int h[64];
		for (int i = 0; i < 64; i++) {
			int row = i / 8;
			for (int j = 0; j < 8; j++) {
				qi[row * 8 + j] = 0;
			}
			h[i] = check(i);
			for (int j = 0; j < 8; j++) {
				qi[row * 8 + j] = maze[row * 8 + j];
			}
		}

		max = 0;
		int pos;
		for (i = 0; i < 64; i++) {
			if (h[i] >= max && maze[i] == 1) {
				max = h[i];
				pos = i;
			}
		}
		int row;
		row = pos / 8;
		int min = 999999;
		int xiao, f = 0;
		for (int i = 0; i < 8; i++) {
			if (h[row * 8 + i] < min && min >= 1) {
				min = h[row * 8 + i], xiao = row * 8 + i, f = 1;
			}
			else if (h[row * 8 + i] == min && min >= 1) {
				int r = rand() % 2;
				if (r == 1) {
					min = h[row * 8 + i], xiao = row * 8 + i, f = 1;
				}
			}
		}

		if (f == 1) {
			for (int i = 0; i < 8; i++) {
				maze[row * 8 + i] = 0;
			}
			maze[xiao] = 1;
		}
		ff = 0;
		for (int i = 0; i < 8; i++) {
			int flag = 0;
			for (int j = 0; j < 8; j++) {
				if (h[i * 8 + j] == 0 && maze[i * 8 + j] == 1) {
					flag = 1;
					break;
				}
			}
			if (flag == 0) {
				ff = 1;
				break;
			}
		}
		if (ff == 0) {
			// 打印结果状态
			return true;
		}
		if (++step >= 50) {
			return false;
		}
	} while (ff != 0);
}

bool first_choice(int n) {
	int i;
	int max;
	int ff;
	int step = 0;
	do {
		for (int i = 0; i < 64; i++) {
			qi[i] = maze[i];
		}

		int h[64];
		for (int i = 0; i < 64; i++) {
			int row = i / 8;
			for (int j = 0; j < 8; j++) {
				qi[row * 8 + j] = 0;
			}
			h[i] = check(i);
			for (int j = 0; j < 8; j++) {
				qi[row * 8 + j] = maze[row * 8 + j];
			}
		}
		int flag, row;

		int time = 0;
		do {
			row = rand() % 8;
			flag = 1;
			for (int i = 0; i < 8; i++) {
				if (h[row * 8 + i] == 0 && maze[row * 8 + i] == 1) {
					flag = 0;
				}
			}
			time++;
			if (time >= 30) break;
		} while (flag == 0);

		int min = 999999;
		int xiao, f = 0;
		for (int i = 0; i < 8; i++) {
			if (h[row * 8 + i] < min && min >= 1) {
				min = h[row * 8 + i], xiao = row * 8 + i, f = 1;
			}
			else if (h[row * 8 + i] == min && min >= 1) {
				int r = rand() % 2;
				if (r == 1) {
					min = h[row * 8 + i], xiao = row * 8 + i, f = 1;
				}
			}
		}

		if (f == 1) {
			for (int i = 0; i < 8; i++) {
				maze[row * 8 + i] = 0;
			}
			maze[xiao] = 1;
		}
		ff = 0;
		for (int i = 0; i < 8; i++) {
			int flag = 0;
			for (int j = 0; j < 8; j++) {
				if (h[i * 8 + j] == 0 && maze[i * 8 + j] == 1) {
					flag = 1;
					break;
				}
			}
			if (flag == 0) {
				ff = 1;
				break;
			}
		}
		if (ff == 0) {
			return true;
		}
		if (++step >= 500) {
			return false;
		}
	} while (ff != 0);

}

void init() {
	
	for (int i = 0; i < 64; i++) {
		maze[i] = 0;
	}
	for (int i = 0; i < 8; i++) {
		int ran = rand() % 8;
		maze[i * 8 + ran] = 1;
	}
	

}

// 随机重新启动法
int randomrestart() {
	bool solve;
	do {
		init();
		solve = hill_climbing(8);
	} while (solve == false);
	double num = 1.0;
	return num;
}

// 最陡爬山法

int steepestascent() {
	int num = 0;
	for (int i = 0; i < 1000; i++) {
		init();
		bool solve = hill_climbing(8);
		if (solve == true) {
			num++;
		}
	}
	return num;
}

// 首选爬山法

int firstchoice() {
	int num = 0;
	for (int i = 0; i < 1000; i++) {
		init();
		bool solve = first_choice(8);
		if (solve == true) {
			num++;
		}
	}
	return num;
}

int main() {
	srand((int)time(0));
	int num1 = randomrestart();
	cout << "1" << endl;
	int num2 = steepestascent();
	cout << "2" << endl;
	int num3 = firstchoice();
	
	cout << endl << endl;
	cout << "随机重新启动法:    " << fixed << setprecision(6) << num1 * 1.0<< endl;
	cout << "最陡上升:    " << fixed << setprecision(6) << num2 / 1000.0 << endl;
	cout << "首选爬山法:    " << fixed << setprecision(6) << num3 / 1000.0 << endl;
	//cout << "最陡上升:    " << fixed << setprecision(6) << num / 1000.0 << endl;
	return 0;
}
</iomanip></time></string></iostream>


八皇后



使用方法:(1)最陡上升法 (2)首项选择法 (3)随即重新启动法



思路:



首先生成随机初始状态。

对于8*8的棋盘,每一行都在这行的随机位置生成一个皇后。



(最陡上升) 思路是: 计算8*8个方格中,每个格子会与多少个皇后发生冲突。得到所有格子的h值后。选择出h值最大的一行,然后在这一行中选出本行h值最小的格子,然后把这一行的皇后放在这个位置上。(这样的依据是: 我们找出一个冲突最多,最需要做出改变的皇后,也即h值最大的行,然后把他放在尽量少冲突的位置上,也即本行中h最小的位置。)

搜索成功的条件是,每行都至少有一个h为0的格子,并且皇后目前的位置在h为0的格子中。(h为0说明在这个位置没有冲突,每一行都有一个没有冲突的位置,并且皇后也在这个位置,就说明所有的皇后都不冲突)

(首项选择) 思路与最陡上升相同,只是在选择下一步的走法时,使用随机选择一行对其作出改变,而不是选出h最大的一行。

(随即重新启动法) 方法和最陡上升一样,不同点在于,如果超过限定的步数,就会重新生成一种摆放状态。重新就行搜索。





实验结果:








由结果知: (1)众所周知,随机重新启动的正确率100%,一定会找到一个正确结果才会结束。

(2)最陡上升效率较低,我进行单步调试后发现原因,效率较低的原因是:它会出现死循环,我们每次要先选择出h值最大行,再找出本行h最小的。此时,就会出现这样的情况,每次h最大的都在同一行,然后在这行中,假如有1-8八个位置,每次选到最小的都是位置2和4.这样就不停的在这两个位置之间跳动,造成死循环。直到到达限制步数

(3)首选爬山法因为没有像最陡上升那样选择,所以大大较少了上述出现的状况,大大提升了命中率。



优化: 对于最陡上升和随机重新启动法做了一些优化。就是在选择下一步的情况时。有可能会出现h相同的结果,这时,我最开始没有管这种情况,直接就是谁先就选谁。这种情况下,命中率只有0.1左右



优化后: 我进行优化的方法是对h相同的进行随机选择,这样效率提高了将近一倍,到达上图的0.18左右。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: