搜索
(1).分类
- 解方案问题 例:(N)个数里选(M)个数,求使这M个数最大的一种方案
- 解数量问题 例:(N)个数里选(M)个数,求使这M个数最大的方案数
- 最优解问题 例:(N)个数里选(M)个数,求这M个数和的最大值
(2).(BFS) 与 (DFS) 的选择问题
(BFS)选择条件:从一个状态转移到另一个状态所需代价是(1) & 最优解问题
例:走迷宫,从一个格子走到另一个格子需要走一步,即代价为(1)
若否,则用(DFS)
(3).剪枝方法:
- 可行性剪枝
- 最优解剪枝
例:(DFS)从(N)个数里选(M)个数,求这(M)个数和的最大值:
inline void DFS(int p,int k,int sum){ //p当前选到第几个数,选了k个数,其和为sum
if(n-p<m-k) return; //可行性剪枝,如果继续搜不可能出现合法的解时,直接结束
if(p>n){ //共n个数
if(k==m) ans=max(ans,sum); //需选m个数
return 0;
}
dfs(p+1,k,sum); //不选
if(k<m) dfs(p+1,k+1,sum+a[p]); //能选的情况下选
}
在保证所有数大于(0)时,求最小值:
inline void DFS(int p,int k,int sum){
if(sum>ans) return; //最优解剪枝,当前的解已经比最优解好,直接结束
if(n-p<m-k) return;
if(p>n){
if(k==m) ans=min(ans,sum);
return 0;
}
dfs(p+1,k,sum);
if(k<m) dfs(p+1,k+1,sum+a[p]);
}
(4).优化技巧
(1).改变搜索顺序优化:(正着搜,倒着搜,随机打乱搜)
inline void DFS(int p,int k,int sum){
if(sum>ans) return; //最优解剪枝,当前的解已经比最优解好,直接结束
if(n-p<m-k) return;
if(p>n){
if(k==m) ans=min(ans,sum);
return 0;
}
if(k<m) dfs(p+1,k+1,sum+a[p]);
//main函数里排序了,从小到大,改变搜索顺序,先选再不选,直接第一次搜索出最优解
//配合最优解剪枝,时间复杂度可以近乎达到O(nlogn)
dfs(p+1,k,sum);
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+n+1); //排序配合最优解剪枝
DFS(1,0,0);
}
(2).随机打乱:
#include<algorithm>
random_shuffle(a+1,a+n+1);
(3).卡时优化:
#include<ctime>
#include<algorithm>
inline void DFS(){
//dfs
}
int main(){
cout<<clock()<<endl;
//clock()函数返回程序运行的时间。
//在Windows系统下,单位为毫秒(ms)
}
注:卡时时不要卡太紧,程序运行退出还会耗用一部分时间
例:卡之前的DFS程序到(900ms),(假设限定时间为(1s))防止TLE
思路:在当前测试点即将TLE时,直接输出答案
TLE一定(0pts),但直接输出不一定(0pts)
#include<ctime>
#include<algorithm>
inline void DFS(){
if(clock()>=900){
//输出答案
exit(0); //直接退出程序
}
}