Editing a Book UVA - 11212(DFS+IDA*)

    You have n equal-length paragraphs numbered 1 to n. Now you want to arrange them in the orderof 1, 2, . . . , n. With the help of a clipboard, you can easily do this: Ctrl-X (cut) and Ctrl-V (paste)several times. You cannot cut twice before pasting, but you can cut several contiguous paragraphs atthe same time - they’ll be pasted in order.

    For example, in order to make {2, 4, 1, 5, 3, 6}, you can cut 1 and paste before 2, then cut 3 andpaste before 4. As another example, one copy and paste is enough for {3, 4, 5, 1, 2}. There are twoways to do so: cut {3, 4, 5} and paste after {1, 2}, or cut {1, 2} and paste before {3, 4, 5}.

Input

    The input consists of at most 20 test cases. Each case begins with a line containing a single integer n(1 < n < 10), thenumber of paragraphs. The next line contains a permutation of 1, 2, 3, . . . , n. Thelast case is followed by a single zero, which should not be processed.

Ouput

    For each test case, print the case number and the minimal number of cut/paste operations.

枚举区间,用IDA*算法剪枝即可。

第一次写这题的时候,总感觉是有什么数学方法能直接解决,想不到了就只有dfs暴力了咯,第一次写时弄错启发函数了,直接超时,参考了刘老师的启发函数才过掉。

中间其实有个技巧,粘贴复制的过程其实相当于两个相邻子区间的互换。互换只要从前往后换即可,因为向前与向后是整体对称的。

还有一点需要强调,bool类型函数默认返回true值而不是false值,我已经两次搞错了,心累啊T_T

AC代码(0ms)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstdlib>
#include<stack>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<sstream>
#include<utility>
#include<ctype.h>
using namespace std;
typedef pair<int,int> Pair;

/* G++ 5.1.0 */
int num[10], a[10];
int maxn, n;

int h() {
	int cnt = 0;
	for(int i=0; i<n-1; i++)
		if(a[i]+1 != a[i+1]) cnt ++;
	if(a[n-1] != n) cnt ++;
	return cnt;
}

bool dfs(int beg) {
	if(beg == maxn) {
		if(h()==0) return true;
		return false;
	}
	if(3*beg + h() > 3*maxn) return false;
	int olda[10], suba[10], subb[10];
	memcpy(olda, a, sizeof(a));
	for(int i=0; i<n; i++)
		for(int j=i; j<n; j++) {
			int  cnt1 = 0;
			for(int k=i; k<=j; k++) suba[cnt1++] = olda[k];
			for(int k=j+1; k<n; k++) {
				int cnt2 = 0;
				for(int t=j+1; t<=k; t++) subb[cnt2++] = olda[t];
				int c1 = 0, c2 = 0;
				for(int t=0; t<n; t++) {
				 	if(t<i) a[t] = olda[t]; else
				 	if(t<i+cnt2) a[t] = subb[c1++]; else
				 	if(t<i+cnt2+cnt1) a[t] = suba[c2++]; else
				 	a[t] = olda[t];
				}
				if(dfs(beg+1)){
					return true;
				}
			}
		}
	return false;
}

int main() {
	int kase = 0;
	while(scanf("%d", &n) && n) {
		maxn = 0;
		int na[10];
		for(int i=0; i<n; i++) scanf("%d", &na[i]);
		memcpy(a, na, sizeof(na));
		printf("Case %d: ", ++kase);
		if(h()==0) printf("0\n"); else
		{
			for(maxn=1; maxn<5; maxn++) {
				memcpy(a, na, sizeof(na));
				if(dfs(0)) break;
			} 
		}
		if(maxn) {
			printf("%d\n", maxn);
		}
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值