IDA*算法是迭代加深的A*算法,同时运用了迭代加深和全局性最优剪枝,与A*算法比起来,具有以下优点: (1).不需要判重,不需要排序 (2).空间需求减少 基本思路: 首先将初始状态结点的H值设为阈值maxH,然后进行深度优先搜索,搜索过程中忽略所有H值大于maxH的结点;如果没有找到解,则加大阈值maxH,再重复上述搜索,直到找到一个解。在保证H值的计算满足A*算法的要求下,可以证明找到的这个解一定是最优解。而这里在IDA*算法中也使用合适的估价函数,来评估与目标状态的距离。 在一般的问题中是这样使用IDA*算法的,当前局面的估价函数值+当前的搜索深度 > 预定义的最大搜索深度时,就进行剪枝。 IDA*算法基本框架:
bool dfs(int depth,int max_depth){
if(depth+f()>max_depth) return false;
if(check()) return true;
return false;
}
int main()
{
int depth=0;
while(!dfs(0,depth)) depth++;
return 0;
}
例题
acwing180.排书 题意: 给定 n 本书,编号为 1~n。在初始状态下,书是任意排列的。在每一次操作中,可以抽取其中连续的一段,再把这段插入到其他某个位置,我们的目标状态是把书按照1~n 的顺序依次排列,求最少需要多少次操作。 思路: 运用IDA*算法,因为每进行一次操作,最多可以使3个无序连接点排序,当序列有序时应满足q[i]==q[i+1]-1,因此可以设tot为当前书的编号序列中q[i]!=q[i+1]-1的连接点,估价函数设为
f
(
s
)
=
?
t
o
t
/
3
?
f(s)=\left \lceil tot/3 \right \rceil
f(s)=?tot/3? 如果当前层数加
f
(
s
)
f(s)
f(s)大于预定义的层数上限,则直接从当前分支回溯
#include<iostream>
#include<algorithm>
#include<queue>
#include<set>
#include<stdlib.h>
#include<time.h>
#include<unordered_map>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<string>
#include<map>
#include<cmath>
#include<bitset>
#define ll long long
#define inf 0x3f3f3f3f
#define bug(a) cout<<"* "<<a<<endl;
#define bugg(a,b) cout<<"* "<<a<<" "<<b<<endl;
#define buggg(a,b,c) cout<<"* "<<a<<" "<<b<<" "<<c<<endl;
using namespace std;
typedef pair<int,int> P;
const int N=15;
const ll mod=1e9+7;
int n;
int q[N];
int w[5][N];
int f(){
int tot=0;
for(int i=0;i<n-1;i++){
if(q[i+1]!=q[i]+1)
tot++;
}
return (tot+2)/3;
}
bool check(){
for(int i=0;i<n;i++){
if(q[i]!=i+1)
return false;
}
return true;
}
bool dfs(int depth,int max_depth){
if(depth+f()>max_depth) return false;
if(check()) return true;
for(int len=1;len<=n;len++){
for(int l=0;l+len-1<n;l++){
int r=l+len-1;
for(int k=r+1;k<n;k++){
memcpy(w[depth],q,sizeof(q));
int x,y;
for(x=r+1,y=l;x<=k;x++,y++)
q[y]=w[depth][x];
for(x=l;x<=r;x++,y++)
q[y]=w[depth][x];
if(dfs(depth+1,max_depth)) return true;
memcpy(q,w[depth],sizeof(q));
}
}
}
return false;
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&q[i]);
int depth=0;
while(depth<5&&!dfs(0,depth)) depth++;
if(depth>=5)
puts("5 or more");
else
printf("%d\n",depth);
}
return 0;
}
acwing181.回转游戏
#include<iostream>
#include<algorithm>
#include<queue>
#include<set>
#include<stdlib.h>
#include<time.h>
#include<unordered_map>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<string>
#include<map>
#include<cmath>
#include<bitset>
#define ll long long
#define inf 0x3f3f3f3f
#define bug(a) cout<<"* "<<a<<endl;
#define bugg(a,b) cout<<"* "<<a<<" "<<b<<endl;
#define buggg(a,b,c) cout<<"* "<<a<<" "<<b<<" "<<c<<endl;
using namespace std;
typedef pair<int,int> P;
const int N=24;
const ll mod=1e9+7;
int op[8][7]={
0,2,6,11,15,20,22,
1,3,8,12,17,21,23,
10,9,8,7,6,5,4,
19,18,17,16,15,14,13,
23,21,17,12,8,3,1,
22,20,15,11,6,2,0,
13,14,15,16,17,18,19,
4,5,6,7,8,9,10
};
int q[N];
int center[8]={6,7,8,11,12,15,16,17};
int opsite[8]={5,4,7,6,1,0,3,2};
int path[100];
void operate(int x){
int tmp=q[op[x][0]];
for(int i=0;i<6;i++)
q[op[x][i]]=q[op[x][i+1]];
q[op[x][6]]=tmp;
}
int f(){
int sum[4]={0},res=0;
for(int i=0;i<8;i++)
sum[q[center[i]]]++;
for(int i=1;i<=3;i++)
res=max(sum[i],res);
return 8-res;
}
bool check(){
for(int i=0;i<8;i++)
if(q[center[i]]!=q[6])
return false;
return true;
}
bool dfs(int depth,int max_depth,int last){
if(depth+f()>max_depth) return false;
if(check()) return true;
for(int i=0;i<8;i++){
if(last==opsite[i]) continue;
operate(i);
path[depth]=i;
if(dfs(depth+1,max_depth,i)) return true;
operate(opsite[i]);
}
return false;
}
int main()
{
while(~scanf("%d",&q[0]),q[0]){
for(int i=1;i<N;i++)
scanf("%d",&q[i]);
int depth=0;
while(!dfs(0,depth,-1)) depth++;
if(!depth)
printf("No moves needed");
else
for(int i=0;i<depth;i++)
printf("%c",path[i]+'A');
cout<<endl;
printf("%d\n",q[6]);
}
return 0;
}
|