1. 程式人生 > 其它 >UVA11212 編輯書稿 Editing a Book (IDA*)

UVA11212 編輯書稿 Editing a Book (IDA*)

IDA*

portal

博大精深的演算法,也就是所謂的迭代加深搜尋,適用在dfs裡,是一種通過深度上限和估價函式來限制搜尋樹從而剪枝的方法。

$ maxd $ $g(n)$ $h(n)$ 分別為我們指定的最大搜索深度,當前搜尋深度,樂觀估價函式。其中 $maxd$ 通過列舉得到,接下來通過本題講講樂觀估價函式。

顧名思義,他是在最樂觀的情況下進行的,他代表的是當前深度最樂觀情況下還需要將搜尋樹加深幾層,換句話說,就是至少再進行幾次操作。對於本題我們可以這麼來設計:

考慮 $a$ $b$ $c$ $d$ 四個相鄰序列,假設我們剪下 $b$ 變為 $a$ $c$ $b$ $d$ 那麼最好情況是什麼?就是 $ac$ $cb$ $bd$ 之間相鄰的數都合法了,那麼最多一次我們可以使 $3$ 組合法,進而我們可以得出,對於數列中所有不合法的 $h$ 組數對,最理想情況下我們只需要 $h/3$ 次操作使他變成目標序列。那麼不合法的就變成了 $h(n)/3 + g(n) > maxd$ 再變一下就是 $h(n) + g(n) * 3 > maxd$ 。這就是所謂的估價函式。

剩下的只需要按照他說的剪下就行了。

#include<cstdio>
#include<queue>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cctype>
#include<vector>
#include<string>
using namespace std;
const int N = 15;
int n,depth,flag;
int a[N];
inline 
int evaluate(){ int res = 0; for(int i=1;i<=n;++i)if(a[i] != a[i-1] + 1)res++; return res; } inline void f(int to_start,int from_start,int end,int *p,int *q){ for(int i=to_start,j=from_start;j<=end;++j,++i)p[i] = q[j]; } inline void IDA_star(int now_depth){ int res = evaluate();
if(now_depth * 3 + res > depth * 3)return; if(res == 0)return flag = 1,void(); int b[N],c[N]; memcpy(b,a,sizeof(b)); for(int i=1;i<=n;++i){ if(a[i] != a[i-1] + 1){//不合法 for(int j=i;j<=n;++j){//子段列舉 if(j < n && a[j+1] == a[j] + 1)continue;//合法 if(a[j+1] > a[j])continue;//合法 for(int k=i;k<=j;++k)c[k] = a[k];//存當前子序列 for(int k=j+1;k<=n;++k){//列舉貼上的右節點 if(k < n && a[k+1] == a[k] + 1)continue;//當前點與他後面的合法,不動 f(i,j+1,k,a,a);//就是把當前j+1 ~ k這一段給我們的上面的子序列i~i+k-j,貼上過來 f(i+k-j,i,j,a,c);//子序列裡的貼上過去 IDA_star(now_depth+1); memcpy(a,b,sizeof(a));//回溯 if(flag)return; } } } } } int main(){ int cnt = 0; while(scanf("%d",&n) == 1 && n){ memset(a,0,sizeof(a)); for(int i=1;i<=n;++i)scanf("%d",a+i); flag = 0; for(depth = 0;depth <= n;++depth){ IDA_star(0); if(flag)break; } printf("Case %d: %d\n",++cnt,depth); } }