码迷,mamicode.com
首页 > 其他好文 > 详细

例题7-12 旋转游戏 UVa1343

时间:2015-04-11 18:01:30      阅读:161      评论:0      收藏:0      [点我收藏+]

标签:迭代加深搜索

1.题目描述:点击打开链接

2.解题思路:本题利用迭代加深搜索解决。好久没做这个专题了,感觉这种方法有点力不从心,不会寻找估价函数是硬伤。。。只好学一学别人的代码。

本题要求棋盘中间的8个方格都要是相同的数字。紫书上说是利用状态空间搜索解决,大致模板还是八数码问题的模板。但是写了半天最后WA了,感觉这道题用那个模板写出来会很复杂。最后看别人的代码,才发现大多都是利用迭代加深搜索解决的,代码量也不是很大。因此学习这种方法了。

本题的移动比较复杂,因此应当事先保存A,B,C,D四个方向的位置,后四个方向可以反推出来。同时还要保存要观察的8个格子的位置。接下来,先判断是否就是目标状态,如果不是,进行迭代加深搜索。

首先要明白迭代加深搜索具体是如何操作的:从小到大依次枚举深度上限maxd。对于每一个深度上限,进行dfs,当递归到maxd时,就要判断是否找到了解,如果找到了,就记录或者输出解。不论是否找到了解,都要开始返回,对于找到了解的情况,可以在函数出口处连续返回。

那么如何及时的返回呢?答案就是寻找“估价函数”并“剪枝”。对于本题,可以发现,每次移动最多只能让目标数字多1个,因此可以将min{diff(1),diff(2),diff(3)}作为股价函数。其中diff(i)是目标格子中不等于数字i的个数。这样以来,如果发现最少要移动的步数h()仍然大于maxd-cur,就需要进行剪枝。

需要注意的是,迭代加深搜索必须在解一定存在的情况下使用,否则会产生无限递归。

3.代码:

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<functional>
using namespace std;

int maxd, ok;
int a[50];
char ans[1000];
int line[8][7] = {
	{ 0, 2, 6, 11, 15, 20, 22 }, // A
	{ 1, 3, 8, 12, 17, 21, 23 }, // B
	{ 10, 9, 8, 7, 6, 5, 4 }, // C
	{ 19, 18, 17, 16, 15, 14, 13 }, // D
};
const int rev[8] = { 5, 4, 7, 6, 1, 0, 3, 2 };//通过A,B,C,D,反推其他方向。指向反向,用来还原现场。
const int final[8] = { 6, 7, 8, 11, 12, 15, 16, 17 };//最后答案要求的点
bool is_final()
{
	for (int i = 1; i < 8; i++)
	if (a[final[i]] != a[final[0]])
		return false;
	return true;
}//终态
int diff(int k)
{
	int ans = 0;
	for (int i = 0; i < 8; i++)
	if (a[final[i]] != k)
		ans++;
	return ans;
}
int h() {//估值函数
	return min(min(diff(1), diff(2)), diff(3));
}
void move(int k)//按照方向移动
{
	int tmp = a[line[k][0]];
	for (int i = 0; i < 6; i++)
		a[line[k][i]] = a[line[k][i + 1]];
	a[line[k][6]] = tmp;
}
void dfs(int cur)
{
	if (is_final())
	{
		ans[cur] = '\0';
		printf("%s\n", ans);
		ok = 1;
		return;
	}
	if (cur + h() > maxd) return;//剪枝
	for (int i = 0; i < 8; i++)
	{
		ans[cur] = 'A' + i;
		move(i);
		dfs(cur + 1);
		if (ok) return;
		move(rev[i]);//还原现场
	}
}
void init()//反推方向
{
	for (int i = 4; i < 8; i++)
	for (int j = 0; j < 7; j++)
		line[i][j] = line[rev[i]][6 - j];
}
int main()
{
	//freopen("t.txt", "r", stdin);
	init();
	while (scanf("%d", &a[0]) == 1 && a[0])
	{
		for (int i = 1; i < 24; i++) scanf("%d", &a[i]);
		for (int i = 0; i < 24; i++)
		if (!a[i])     return 0;
		ok = 0;
		if (is_final())
			printf("No moves needed\n");
		else
		for (maxd = 1;; maxd++)
		{
			dfs(0);
			if (ok)   break;
		}
		printf("%d\n", a[6]);//最终的颜色
	}
	return 0;
}

例题7-12 旋转游戏 UVa1343

标签:迭代加深搜索

原文地址:http://blog.csdn.net/u014800748/article/details/44996065

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!