IDA* uva 旋转游戏(the rotating game)

显然直接枚举全排列数据太大了,而且有很多不必要的操作。这是一道明显的状态搜索题,那么该采用什么方法呢? bfs?迭代bfs?A*?还是双向bfs

这题用双向bfs和a都可以做出来,但是相比之下,A会比双向bfs快一点。
既然选择了a*就要考虑如何找启发式函数了,经过分析,每次经过一次旋转的话对于一个状态的改变量只有1个(不是3个!一开始自己以为是3个状态改变就错了),因为这个是与顺序无关的,比如 4 2 3 1 5 对于中间3个的状态开始时2 3 1,向右旋转一次 x(4前面的一个数,没写出来)4 2 3 5,此时中间的状态就是4 2 3,又因为和顺序没关系,就是多了一个4进来而已,也就改变了一个而已。

还有一个就是一开始想估计maxd,最深 有多少,但是自己能力有限也没有想出来,只好用迭代加深搜索法了(某种意义上,迭代可能还更好),代码如下。

最后就是学会这道题隐式图的建立方法,不要用7×7的二维数组建立,太浪费空间了,操作也会变得麻烦一些。

总结:scanf("%d "…) 这是错的,别随便加空格啊,卡了半天。
以及 a='a ’ 这种,也别随便加空格。这种小细节注意,不然卡死人。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
int line[8][7] = {              //8个方向,每个方向7个数的编号。
  { 0, 2, 6,11,15,20,22},    // A-H
  { 1, 3, 8,12,17,21,23},
  {10, 9, 8, 7, 6, 5, 4},
  {19,18,17,16,15,14,13},
  {23,21,17,12,8,3,1},
  {22,20,15,11,6,2,0},
  {13,14,15,16,17,18,19},
  {4,5,6,7,8,9,10},
};
const int rev[8] = { 5,4,7,6,1,0,3,2 }; //上面数组每行对应的一行,比如a对应f,a在0,f在5
const int center[8] = { 6, 7, 8, 11, 12, 15, 16, 17 };
char mirror[8]={'F','E','H','G','B','A','D','C'};
int a[24]; //存每个编号的数字
char ans[1000];

bool is_final1() {
	for (int i = 0; i < 8; ++i) {
		if (a[center[0]] != a[center[i]]) {
			return false;
		}
	}
	return true;
}

int diff(int k) {                     //就是看中间8个有多少与k不同,k取1或者2或者3
	int ans = 0;
	for (int i = 0; i < 8; ++i) {
		if (k != a[center[i]]) {
			++ans;
		}
	}
	return ans;
}
 int h() {
	return min(min(diff(1), diff(2)), diff(3));	
}

 void move(int i) {
	int tmp = a[line[i][0]];
	for (int j = 0; j < 6; ++j) {
		a[line[i][j]] = a[line[i][j + 1]];
	}
	a[line[i][6]] = tmp;
}
bool dfs(int d,int maxd) {
	if (is_final1()) {
		ans[d] = '\0';
		printf("%s\n", ans);
		return true;
	}
	if (h() > 1 * (maxd - d)) return false;
	for (int i = 0; i < 8; ++i) {
		ans[d] = 'A' + i;
		if(d>0&&ans[d-1]==mirror[i]) continue;  //提速。 
		move(i);
		if (dfs(d + 1, maxd)) return true;
		move(rev[i]);  //回溯
	}
	return false;
}
int main() {
	while (scanf("%d", &a[0]) == 1 && a[0]) {
		for (int i = 1; i < 24; ++i) scanf("%d", &a[i]);

		if (is_final1()) {
			printf("No moves needed\n");
		}
		else {
			for (int i = 1;; ++i) {
				if (dfs(0, i)) break;
			}

		}
		printf("%d\n", a[6]);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值