【总结】迭代加深

Power Calculus

不难想到以下剪枝:

  • 每次操作新生成的数,当 > n >n >n 时必须执行减法,当 < n <n <n 时必须执行加法,尽量选数值大的数

  • 数列中的数必须不重复

  • 若每次乘二都不能到达 n n n ,则退出

然而第一种做法无法搜出来答案,主要是在于前面部分可能执行一次减法,而上述方法是先将加法搜完,相当于是搜一个没有答案的很深的子树。实际上关键是在前几次搜索的选择上。考虑换一种搜索顺序,加法和减法同时搜,同时优先搜加法。然而担忧在于初始时分支太多。但是如果不这样做,又不能找到正确答案所在的子树。不过,由于有了第三条剪枝,所以顺利搜出来了。

这个搜索顺序值得玩味。

473

11

1 2 4 8 16 32 64 128 256 192 384

0 1 2 3 4 5 6 7 8 9 10 11

编辑书稿

设层数为k,则总操作数为 56 0 k 560^k 560k

先考虑不加任何优化的暴力+迭代加深。无法通过,层数太深。

用数组来存储空间消耗太大,可以考虑用整数来状压。(然而实测这种方法更慢)

缩小搜索空间的策略有

策略1:只剪切连续的数字片段

策略2:剪切的片段头为a尾为b,要么粘贴到a-1的后面,要么粘贴到b+1前面。

策略3:不要破坏已经连续的片段。

但是策略1和策略2并能保证正解:如5 4 3 2 1 —》 3 2 5 4 1 —》 3 4 1 2 5 -》 1 2 3 4 5。

策略1,2出错主要是因为忽略了后效性,策略3是可以的,把连续的片段看成整体,拆开它一定是比不拆它的步数要少。

可以发现3个策略都只考虑了端点,由于是控制的决策,所以后效性较大。而策略3则在原有状态空间里保留了已经剪切成功的部分。

下面寻找估价函数

由于每次剪切最多更改3个数字的前继(或后继),所以统计前继不对的数字个数为n个那么只少还要搜n/3层。如果d+n/3>maxd就剪枝。

还有一个剪枝是:移动片段b1-b2到b2+1-c后面,相当于移动b2+1-c到b1-b2前面,所以只要枚举把片段往后移动就行了。

最后一个剪枝在于,为了保证相邻两个数的大小关系不被破坏,所以当 a j < a j + 1 a_j<a_{j+1} aj<aj+1 时, a j a_j aj 会跑到后面,可以剪枝。

#include<bits/stdc++.h>
#define LL long long
using namespace std;
int n,len,a[15];
//瞎写的 
bool dfs(int x,int dep) {
	int cnt=0; for(int i=1;i<=n;i++) if(a[i]!=a[i-1]+1) cnt++;
	if(cnt==0) return 1;
	if(x+(cnt+2)/3>dep) return 0;
	int copy[15];copy[0]=copy[n+1]=0;for(int i=1;i<=n;i++) copy[i]=a[i];
	for(int i=1;i<=n;i++) {
		if(copy[i-1]+1==copy[i]) continue;
		for(int j=i;j<=n;j++) {
	    	if(copy[j]+1==copy[j+1]) continue;
	    	if(copy[j]<copy[j+1]) continue;
	    	for(int k=j+1;k<=n;k++) {
	    		if(copy[k]+1==copy[k+1]) continue;
	    		int cnt=0;
	    		for(int s=1;s<i;s++) a[++cnt]=copy[s];
	    		for(int s=j+1;s<=k;s++) a[++cnt]=copy[s];
	    		for(int s=i;s<=j;s++) a[++cnt]=copy[s];
	    		for(int s=k+1;s<=n;s++) a[++cnt]=copy[s];
	    		if(dfs(x+1,dep)) return 1;
			}
		} 
	}
	for(int i=1;i<=n;i++) a[i]=copy[i];
	return 0;
}
signed main() {
//	freopen("data6.in","r",stdin);
//	freopen("own.out","w",stdout);
	int T=0;
	while(scanf("%d",&n)&&n) {
		for(int i=1;i<=n;i++) scanf("%d",&a[i]);
		for(len=0;len<=n;len++) {
			if(dfs(0,len)) {
		    	break;
		    }
		} 
		printf("Case %d: %d\n",++T,len);
	}
}

Derorying the station

不难想到,满足条件的充要条件是最短路长度<=k。

想要满足条件,就必须在最短路上删除一个点。

我们可以以此为搜索框架,进行迭代加深搜索。每次搜索时,一直在最短路上选一个点来删除,直到没有路或路大于等于k。

求最短路时间复杂度是 O ( 50 ) O(50) O(50)。每层搜索最多有50个分支(比直接随便选一个点来好很多,因为有可能白删除了),可以接受。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值