uva 11212 Editing a Book

题目:Editing a Book


题意:有一本有n段的书,段的编号为1~n,段的顺序是乱的。有“剪切”和“粘贴”的两种操作,问至少要用多少组剪切和粘贴才能把顺序调整正确。


思路:

IDA*。

估价函数为:h>3*(maxd-d)。h代表前后不匹配 (如果a[i]-a[i-1]==1,那么i与i-1匹配) 的段的个数。由于每次操作h最多加大3 (如书上图,假设a的最后一个数和b的前一个数不连续,b的最后一个数和c的前一个数不连续,c的最后一个数和后面空白的前一个数不连续,调度后它们都变得连续,那么匹配数为1,这是最优情况) ,而剩下只有maxd-d次操作的机会,所以最多只能让3*(maxd-d)个不匹配的段匹配。如果此时不匹配的段更多,那么搜完前一定不能完全匹配,可以剪枝。

还有不能拆开已经变成连续了的序列,如书中【策略3】。



代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<sstream>
#include<queue>
using namespace std;

int n;
string a;
int maxd;

int find(string y) {
	int sum=0;
	for(int i=0; i<y.size()-1; i++) {
		if(y[i+1]-y[i]!=1) ++sum;
	}
	return sum;
}

bool dfs(int d,string a) {
	if(d==maxd) {
		for(int i=0; i<a.size(); i++) {
			if(a[i]-'0'!=i+1) return false;
		}
		return true;
	}
	for(int i=0; i<a.size(); i++) {
		if(i!=0&&a[i]-a[i-1]==1) continue;
		for(int j=i; j<a.size(); j++) {
			string x=a.substr(i,j-i+1);
			if(j!=a.size()-1&&a[j+1]-a[j]==1) continue;
			string after=a.substr(j+1,a.size()-j-1);
			string before=a.substr(0,a.size()-x.size()-after.size());
			for(int k=0; k<after.size(); k++) {
				string y=before+after.substr(0,k+1)+x+after.substr(k+1,after.size()-k-1);
				int h=find(y);
				if(h>3*(maxd-1-d)) continue;
				if(dfs(1+d,y)) return true;
			}
		}
	}
	return false;
}

int main() {
	int T=0;
	while(scanf("%d",&n)==1&&n!=0) {
		a.clear();
		for(int i=0; i<n; i++) {
			int x;
			scanf("%d",&x);
			a+=(char)(x+'0');
		}
		for(maxd=0; maxd<n; maxd++) {
			if(dfs(0,a)) {
				printf("Case %d: %d\n",++T,maxd);
				break;
			}
		}
	}
	return 0;
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值