关于几种进阶搜索算法

双向搜索

这种优化可以显著降低时间空间复杂度,分为两类:

双向宽搜
相当于同时从起点和终点跑普通宽搜,两边各自扩展自己的层级。关键是要实时检查两边探索到的状态是否有交集,一旦发现交集状态就说明找到了连接路径,可以立即停止。

双向深搜

主要解决状态空间巨大的问题。思路是:

  1. 把问题状态空间分成两半
  2. 对每半单独跑DFS搜索
  3. 把所有合法答案分别存入两个数组
  4. 最后用二分查找/双指针拼出最终答案

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;
}
posted @ 2025-08-14 08:35  PX侠客行  阅读(13)  评论(0)    收藏  举报