关于几种进阶搜索算法
双向搜索
这种优化可以显著降低时间空间复杂度,分为两类:
双向宽搜
相当于同时从起点和终点跑普通宽搜,两边各自扩展自己的层级。关键是要实时检查两边探索到的状态是否有交集,一旦发现交集状态就说明找到了连接路径,可以立即停止。
双向深搜
主要解决状态空间巨大的问题。思路是:
- 把问题状态空间分成两半
- 对每半单独跑DFS搜索
- 把所有合法答案分别存入两个数组
- 最后用二分查找/双指针拼出最终答案
A*算法
这是启发式的智能搜索,核心在于它的估价函数:
如果去掉估价函数 \(h(n)\),它就退化成了普通的Dijkstra
算法运行时同时考虑:
1.从起点到当前的实际代价 \(g(n)\)
2.到目标的预估代价 \(h(n)\)
优先扩展 \(f(n) = g(n) + h(n)\) 最小的状态
为什么高效?
普通搜索是"盲目"的,而好的估价函数像指路明灯,引导算法避开死胡同直奔目标。注意 \(h(n)\)必须是乐观估计才能保证找到最优解
迭代加深搜索
专门解决这种困境:答案可能在浅层,但错误分支又深又长
核心操作:
1. 先限制深度跑DFS
2. 如果没找到答案,深度+1
3. 重新开始DFS
循环直到找到答案
优势:
像宽搜一样能找到最浅解
像深搜一样省内存
避免陷在错误分支做无用功
代价:
浅层节点会被重复搜索,但这点额外开销通常是值得的
附上模板代码
双向dfs:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=200000005;
int g[70],ans=-1e9,n,w,k,cnt,a[N],half;
void dfs1(int x,int t){
if(x==half){
a[++cnt]=t;
return;
}
dfs1(x+1,t);
if(t+g[x]<=w){
dfs1(x+1,t+g[x]);
}
}
void sovle(int val){
int l=1,r=cnt;
int ww=w-val;
while(l<r){
int mid=(l+r+1)>>1;
if(a[mid]<=ww){
l=mid;
}
else{
r=mid-1;
}
}
ans=max(a[l]+val,ans);
}
void dfs2(int x,int t){
if(x==n+1){
sovle(t);
return;
}
dfs2(x+1,t);
if(t+g[x]<=w){
dfs2(x+1,t+g[x]);
}
}
signed main(){
cin>>w>>n;
for(int i=1;i<=n;i++){
cin>>g[i];
}
sort(g+1,g+n+1,greater<int>());
half=(n>>1)+3;
dfs1(1,0);
sort(a+1,a+cnt+1);
cnt=unique(a+1,a+cnt+1)-(a+1);
dfs2(half,0);
cout<<ans;
return 0;
}
双向宽搜
#include <bits/stdc++.h>
using namespace std;
int s,e=123804765;
int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};
queue<int>q;
map<int,int>vis;
map<int,int>ans;
int a[100][100];
int main(){
cin>>s;
if(s==e){
cout<<0;
return 0;
}
q.push(s);
q.push(e);
vis[s]=1;
vis[e]=2;
ans[s]=0;
ans[e]=1;
while(!q.empty()){
int fx,fy;
int front,end=q.front();
q.pop();
front=end;
for(int i=3;i>=1;i--){
for(int j=3;j>=1;j--){
a[i][j]=front%10,front/=10;
if(a[i][j]==0) fx=i,fy=j;
}
}
for(int i=0;i<4;i++){
int xx=fx+dx[i];
int yy=fy+dy[i];
if(xx>=1&&xx<=3&&yy>=1&&yy<=3){
swap(a[fx][fy],a[xx][yy]);
front=0;
for(int j=1;j<=3;j++){
for(int k=1;k<=3;k++){
front=front*10+a[j][k];
}
}
if(vis[front]==vis[end]){
swap(a[fx][fy],a[xx][yy]);
continue;
}
if(vis[front]+vis[end]==3){
cout<<ans[front]+ans[end]<<"\n";
return 0;
}
ans[front]=ans[end]+1;
vis[front]=vis[end];
q.push(front);
swap(a[fx][fy],a[xx][yy]);
}
}
}
return 0;
}
迭代加深
#include <bits/stdc++.h>
using namespace std;
int mapp[10][10];
int t,sx,sy;
int dx[8]={-2,-2,-1,1,-1,1,2,2};
int dy[8]={-1,1,2, 2,-2,-2,-1,1};
int to[20][20]={
{0,0,0,0,0,0},
{0,1,1,1,1,1},
{0,0,1,1,1,1},
{0,0,0,2,1,1},
{0,0,0,0,0,1},
{0,0,0,0,0,0},
};
int pd(){
int sum=0;
for(int i=1;i<=5;i++){
for(int j=1;j<=5;j++){
if(mapp[i][j]!=to[i][j]){
sum++;
}
}
}
return sum;
}
bool fl;
void dfs(int k,int x,int y,int dep,int last){
if(k==dep+1){
if(pd()==0){
fl=1;
}
return;
}
for(int i=0;i<8;i++){
if(i==7-last) continue;
int xx=x+dx[i];
int yy=y+dy[i];
if(xx<1||yy<1||xx>5||yy>5) continue;
swap(mapp[xx][yy],mapp[x][y]);
if(k+(pd()+1)/2<=dep){
dfs(k+1,xx,yy,dep,i);
}
swap(mapp[xx][yy],mapp[x][y]);
}
}
int main(){
cin>>t;
char ch;
while(t--){
memset(mapp,0,sizeof(mapp));
fl=0;
for(int i=1;i<=5;i++){
for(int j=1;j<=5;j++){
cin>>ch;
if(ch=='*'){
mapp[i][j]=2;
sx=i,sy=j;
}
else{
mapp[i][j]=ch-'0';
}
}
}
if(pd()==0){
cout<<"0\n";
continue;
}
for(int i=1;i<=15;i++){
dfs(1,sx,sy,i,-1);
if(fl){
cout<<i<<"\n";
break;
}
}
if(!fl){
cout<<"-1\n";
}
}
return 0;
}

浙公网安备 33010602011771号