当前位置: 首页 > news >正文

关于几种进阶搜索算法

双向搜索

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

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

双向深搜

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

  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;
}
http://www.sczhlp.com/news/11465/

相关文章:

  • 数据中心“拥抱”ARM架构,为何如此艰难?
  • ZROI 集训模拟赛后感
  • VLA完成度较低,加入世界模型或能收窄不确定性
  • 一文搞懂多模态大模型:视觉-语言模型(VLM)
  • 20250813(补档)
  • 8月集训记
  • 中国高校的AI大神教授盘点
  • VS Code 中把「自己部署的 Coder 模型」变成 AI 编程助手
  • 美版宇树|全球最灵敏人形机器人叠衣服,不只是机械臂!力证VLA模型?
  • AI自我提升的五种技术路径
  • C#记录类型与集合的深度解析:从默认行为到自定义比较
  • 【指南】同时安装vllm与flashinfer
  • 记一次展讯CPU安卓手机刷成砖后的救砖记录
  • Java集合——11.使用PriorityQueue
  • 基础算法
  • C++小白修仙记_快速排序
  • Java集合——10.使用Queue
  • 树链剖分详解(长链剖分)
  • 圆锥曲线二级结论
  • 新版EIDE创建C51_with_keil5模板方法
  • 【日记】2025-8-13
  • 谷歌账号停用申诉 google账户被封如何解封 如何填写申诉理由和找回账号
  • CompletableFuture
  • 大東聰明家App技术支持
  • 【碎碎念】无题
  • 联想Lenovo R7000P-2025款 安装 Ubuntu linux 后没有 mt7925 网卡驱动(网卡不能正常运行或无法识别)的解决方案
  • 【LeetCode 199】力扣算法:二叉树的右视图
  • SPI与菊花链
  • Java集合——9.使用Set
  • vue基础