2020.10.1 清北学堂 J2综合强化营 D1 搜索笔记

搜索

\(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);	//直接退出程序
	}
}
posted @ 2020-10-02 11:58  _pwl  阅读(306)  评论(2)    收藏  举报
1 2 3
4