例题7-10 编辑书稿 UVa11212

本博客介绍如何利用迭代加深搜索策略解决UVa11212编辑书稿的问题。该问题是一个状态空间搜索问题,初始状态为输入排列,目标状态为1到n的有序排列。考虑到排列数量限制(n≤9),虽然可能状态较多,但通过迭代加深搜索并结合有效的剪枝策略(如当错误数字个数h大于3*(最大深度-d)时剪枝),可以在不超过8步的情况下找到解决方案。文章提供了详细的解题思路及代码实现。
摘要由CSDN通过智能技术生成

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

2.解题思路:本题利用迭代加深搜索,也是一道典型的状态空间搜索问题,状态就是1~n的排列,初始状态是输入,终止状态是1,2,……n。由于n≤9,排列最多有9!=362880个,但由于每个状态的后继状态比较多,因此仍有TLE的危险。本题如果利用迭代加深搜索,可以发现做多只需要8步,关键在于如何有效地剪枝。考虑后继不正确的数字的个数h,可以证明每次剪切时h最多减少3(因为一次剪切最多只会改变3个数字的后继,若剪切后这3个数字的后继都正确,则h最多减少了3),因此当h>3*(maxd-d)时剪枝即可。

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<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;

const int maxn = 12;
int arr[maxn];
int maxd, n;
struct node
{
	int v[maxn];
};
int geth(int*a)//计算后继不正确的项的个数
{
	int cnt = 0;
	for (int i = 0; i < n;i++)
	if (a[i] + 1 != a[i + 1])
		cnt++;
	return cnt;
}
void moveTo(node&s, node&t, int i, int j, int k)
{
	int num = j - i + 1;//要移动的个数
	for (int u = 0; u < num; u++)//把原来i到j之间的数移到k后面
		t.v[k + u] = s.v[i + u];
	num = i - k;
	for (int u = 0; u < num; u++) //把原来k到i之间(不包括i)的数移到k+j-i后面
		t.v[j - u] = s.v[i - 1 - u];
}
bool dfs(int d, node t)
{
	if (geth(t.v)>3 * (maxd - d))return false;
	if (geth(t.v) == 0)return true;

	node next;
	for (int i = 0; i < n;i++)
	for (int j = i; j < n;j++)
	for (int k = 0; k < i; k++)
	{
		memcpy(next.v, t.v, sizeof(t.v));
		moveTo(t, next, i, j, k);
		if (dfs(d + 1, next))return true;
	}
	return false;
}
int main()
{
	int v = 0;
	while (scanf("%d", &n)&&n)
	{
		for (int i = 0; i < n; i++)
			scanf("%d", arr + i);
		arr[n] = n + 1;//辅助后面判断h的大小
		int tmp = 0;
		tmp = geth(arr);
		node a1;
		memcpy(a1.v, arr, sizeof(arr));
		if (tmp)
		{
			for (maxd = 1;;maxd++)
			if (dfs(0, a1))break;
		}
		printf("Case %d: ", ++v);
		if (!tmp)
			printf("0\n");
		else printf("%d\n", maxd);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值