详解各类搜索
深搜
inline void dfs(int x)
{
dfs();
}
广搜
inline void bfs()
{
queue<int> q;
q.push(···)
while(!q.empty())
{
···
}
}
记忆化搜索
其实就是记录了每一种状态的最优值,达到玄学剪枝效果。。。
例题:单词游戏
代码:
#include <bits/stdc++.h>
using namespace std;
const int N=20;
int n,vis[N],len[N];
string s[N];
int maxx=0,f[N][1<<N];
inline int dfs(int x,int y,int id)
{
if(f[x][y])return f[x][y];
int t=0;
for(int i=1;i<=n;i++)
{
if(vis[i])continue;
vis[i]=1;
if(id==0||s[id][len[id]-1]==s[i][0])t=max(t,dfs(i,(y|(1<<(i-1))),i));
vis[i]=0;
}
return f[x][y]=t+len[x];
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
cin>>s[i];
len[i]=s[i].size();
}
for(int i=1;i<=1000;i++)dfs(0,0,0);
for(int i=1;i<=n;i++)
{
for(int j=0;j<(1<<n);j++)
{
maxx=max(maxx,f[i][j]);
}
}
cout<<maxx;
return 0;
}
迭代加深搜索
定义
迭代加深搜索也叫 ,是一种每次限制搜索深度的深度优先搜索。
解释
迭代加深搜索的本质还是深度优先搜索,只不过在搜索的同时带上了一个深度 ,当 达到设定的深度时就返回,一般用于找最优解。如果一次搜索没有找到合法的解,就让设定的深度加一,重新从根开始。
代码
inline int dfs(int x)//x:深度
{
if(x>mxd)return ;//mxd:当前设定的最大深度
······
······
}
例题:Addition Chains
#include <bits/stdc++.h>
using namespace std;
const int N=10005;
int t,n,ans[N],mxd;
inline int dfs(int x)
{
if(x>mxd)return ans[x-1]==n;
if(ans[x-1]*(long long)(1ll<<(mxd-x+1))<n)return 0;
for(int i=0;i<x;i++)
{
for(int j=0;j<x;j++)
{
int s=ans[i]+ans[j];
if(s>n)break;
if(s<=ans[x-1])continue;
ans[x]=s;
if(dfs(x+1))return 1;
}
}
return 0;
}
int main()
{
ans[0]=1;
while(1)
{
scanf("%d",&n);
if(n==0)break;
cout<<'1';
for(mxd=0;;mxd++)
{
if(dfs(1))
{
for(int i=1;i<=mxd;i++)
{
cout<<' '<<ans[i];
}
cout<<'\n';
break;
}
}
}
return 0;
}
注意
- 在大多数的题目中,广搜还是比较方便的,而且容易判重。当发现广搜在空间上不够优秀,而且要找最优解的问题时,就应该考虑迭代加深
- 一般在求最少步数类似的题目中可以考虑使用迭代加深
折半搜索(meet in the middle)
简化意思:把暴力分成两部分进行搜索,再把两个的结果融合。
例题:Balanced Cow Subsets G(双倍经验)
纯暴力: 显然不能过
折半搜索: 可以通过~~
思路:总共搜索两次——一次处理前半部分的情况,一次处理后半部分的情况。
代码(题解写法):
#include <bits/stdc++.h>
using namespace std;
const int N=22;
int n,a[N];
map<int,int> id;//由于值域过大,卡了我好久,一直想不到,感觉还挺妙的qwq
int ans[1<<N],tot=0;
vector<int> k[1<<N];
inline void dfs1(int x,int sum,int now)
{
if(x>n/2)
{
if(id[sum]==0)id[sum]=++tot;
k[id[sum]].push_back(now);
return;
}
dfs1(x+1,sum+a[x],now|(1<<(x-1)));
dfs1(x+1,sum-a[x],now|(1<<(x-1)));
dfs1(x+1,sum,now);
}
inline void dfs2(int x,int sum,int now)
{
if(x>n)
{
int u=id[sum];
if(u!=0)for(int i=0;i<k[u].size();i++)ans[k[u][i]|now]=1;
return;
}
dfs2(x+1,sum+a[x],now|(1<<(x-1)));
dfs2(x+1,sum-a[x],now|(1<<(x-1)));
dfs2(x+1,sum,now);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
dfs1(1,0,0);
dfs2(n/2+1,0,0);
int cnt=0;
for(int i=1;i<(1<<n);i++)cnt+=ans[i];
cout<<cnt;
return 0;
}
与
:对当前状态进行估价(是否能够得到答案)
:在 的基础上,再加上迭代加深的思想
例题:骑士精神
#include <bits/stdc++.h>
using namespace std;
const int N=10;
int T,h[N][N],b[N][N],k,n=5;
bool judge=0;
int a[N][N]={
{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 d[8][2]={{1,2},{1,-2},{2,1},{2,-1},{-2,1},{-2,-1},{-1,2},{-1,-2}};
void init()
{
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)h[i][j]=b[i][j];
}
int test(int s)//估价函数:test
{
int sum=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(a[i][j]!=h[i][j])
if((++sum+s)>k)
return 0;
}
}
return 1;
}
int check()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(a[i][j]!=h[i][j])return 0;
}
}
return 1;
}
void A(int s,int x,int y)
{
if(s==k)
{
if(check())judge=1;
return;
}
if(judge==1)return;
for(int i=0;i<=7;i++)
{
int tx=x+d[i][0],ty=y+d[i][1];
if(tx<1||ty<1||tx>n||ty>n)continue;
swap(h[x][y],h[tx][ty]);//一定要在if外swap,这里我调了N久
if(test(s)&&judge==0) A(s+1,tx,ty);
swap(h[x][y],h[tx][ty]);
}
}
void solve()
{
int flag=0,xx=0,yy=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
char c;
cin>>c;
if(c=='*')h[i][j]=2,xx=i,yy=j;
else h[i][j]=c-'0';
b[i][j]=h[i][j];
}
}
judge=0;
for(k=0;k<=15;k++)//类似迭代加深(iddfs)
{
init();
A(0,xx,yy);
if(judge)
{
cout<<k<<'\n';
return;
}
}
cout<<-1<<'\n';
return;
}
int main()
{
scanf("%d",&T);
while(T--)solve();
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!