【总结】迭代加深

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个分支(比直接随便选一个点来好很多,因为有可能白删除了),可以接受。


__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530349.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(20)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示