UVa11212,Editing a Book
正如书上所说,本题需要用IDA*算法求解
启发函数是3d+h>3maxd(d为当前操作步骤数,h为当前逆序对数,maxd为当前枚举的最大步骤数)
可见迭代递归的核心思想是枚举ans去dfs是否可行,相反常规搜索是dfs去需找ans。
一开始卡在状态图的转移与回溯上,参考(http://blog.csdn.net/sssogs/article/details/8836606)大神的代码后得到启发,可以将图或是表直接写成结构体或是类跟着递归走(当然,图或是表不能很大,比较大的话应该还是用回溯比较好吧)
#include <iostream> #include <cstring> #include <cstdio> #include <string> #include <algorithm> #define maxn 20 using namespace std; int maxd,cnt; class MyClass{ public: int map[maxn]; int h,n; void move(int s,int e,int k){ int t[maxn]; for (int i=0;i<k;i++){ t[i]=map[i]; } for (int i=s;i<=e;i++){ t[k+i-s]=map[i]; } int top=k+e-s; for (int i=k;i<n;i++){ if (i<s||i>e) t[++top]=map[i]; } memcpy(map,t,sizeof(t)); } void move2(int s,int e,int k){ int t[maxn],i,j; for (i=0; i<s; i++) { t[i]=map[i]; } for (j=e+1; j<k; j++,i++) { t[i]=map[j]; } for (j=s; j<=e; j++,i++) { t[i]=map[j]; } for (j=k; j<n; j++,i++) { t[i]=map[j]; } memcpy(map,t,sizeof(t)); } int getH(){ h=0; for (int i=0;i<n-1;i++) if (map[i]+1!=map[i+1]) h++; if (map[n-1]!=n) h++;//经过测试,这一句减掉了60%的搜索量.......之前一直TLE,天呢,又是一下午 return h; } bool init(){ cin>>n; if (n==0) return false; for (int i=0;i<n;i++){ cin>>map[i]; } return true; } }; int IDAdfs(int d,MyClass c){ c.getH(); MyClass tc; cnt++; if (c.h==0) return 1; //if (d==maxd&&c.h>0) return 0; if (3*d+c.h>3*maxd) return 0; for (int i=0;i<c.n;i++) for (int j=i;j<c.n;j++){ for (int k=0;k<i;k++){ tc=c; tc.move(i,j,k); if (IDAdfs(d+1,tc)) return 1; } for (int k=j+2; k<c.n; k++) { tc=c; tc.move(i,j,k); if (IDAdfs(d+1,tc) == true) return true; } } return 0; } int main() { MyClass b; int prob; prob=1; while (b.init() == true) { cnt=0; for (maxd=0; ; maxd++) { if (IDAdfs(0,b) == true) break; } printf("Case %d: %d\n",prob,maxd); prob++; //cout<<cnt<<endl; } }