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);	//直接退出程序
	}
}
原文地址:https://www.cnblogs.com/-pwl/p/13760783.html