说明:
1.该讲解主要针对已经大致学过搜索,但是想复习或想提高能力或正在备战NOIP的oier
2.红色字体为重点
简介:不加优化的DFS效率很低,常常用于暴力枚举,在NOIP考试中直接考察裸的搜索概率不大。
常用方面:枚举子集,枚举排列,搜索枚举答案,图或树的遍历
模板:
void dfs(int i, ...){
if(i==边界){
处理;
return 0;
}
for(枚举所有状态){
其他处理;
dfs(i+1, ...);
其他处理;
}
}
简介:DFS+剪枝与DFS不同就在于剪枝,加上适当的剪枝的DFS速度会极大的加快,往往考察DFS+剪枝的题分数取决于你剪枝的强度,在早年的NOIP考试中经常考察,而且常常作为压轴题出现,近年来考察力度有所减少,但它还是面对写不了正解的题的得分利器。
常用方面:需要枚举答案或数据范围偏小的题
模板:
void dfs(int i, ...){
if(i==边界){
处理;
return 0;
}
if(满足剪枝条件) return;//不再搜索下面的状态,剪枝
for(枚举所有状态){
其他处理;
dfs(i+1, ...);
其他处理;
}
}
我们先看一个简单的例子:
时间限制:5秒 内存限制:64M
【问题描述】
射击运动员每次训练他都会连续打出 n 发子弹,他只有平均达到或超过 9 环才算通过。现请你编程计算出通过共有哪些情况。每发子弹击中的环数是一个 0-10 之间的整数,0 环表示脱靶,10 环表示击中靶心。
【输入格式】
仅一行,包含一个正整数n,表示打出的子弹数。
【输出格式】
若干行,每行由 n 个用空格隔开的数字组成,表示某一组符合条件的环数(按N个数字排列的字典序输出)。最后一行输出一个数,表示符合条件的总方案数。
【数据范围】
1 <= n <= 11
分析:
单纯搜索:
我们直接搜索他每一次可以打的环数,然后判断是否满足条件就可以了
时间复杂度O(11^n),肯定要超时
代码:
#include
int ans=0,n,a[12];
void operate(int k,int num){
if(k>n){//边界
if(num>=9*n){//处理
ans++;
for(int i=1;i
优化(剪枝):
我们考虑他已经射击了k-1次,已经共达到sum环,那么如果接下来(从第k次开始)每次射击都是10环都不能使他平均环数达到9环,那么接下来的情况我们就不需要继续搜索了,此时剪枝即可。
剪枝条件:
优化后的代码:
#include
int out[15];
void print(int pnt){//快速输出
int p=0;
if(pnt==0) {putchar('0');return;}
else while(pnt)
out[p++]=pnt%10,pnt/=10;
for(int j=p-1;j>=0;j--) putchar('0'+out[j]);
}
int ans=0,n;
int a[12];
void operate(int k,int num){
if(k>n){//边界
if(num>=9*n){//处理
ans++;
for(int i=1;i
优化后速度提升是巨大的,再加上快速输出优化,我的程序运行速度轻松达到榜首
拓展训练(题目推荐):
接下来的题目难度开始加大了,其中大部分是当年NOIP的压轴题,均需要有足够强的剪枝才能通过,如果做不来请看讲解。
T1:
难度:XX(基础题)
题目:(NOIP2001)数的划分 题解:见T2
T2:
难度:XXXX(难题,下同)
题目:(NOIP2003)传染病控制 题解:见T4
T3:
难度:XXXX
题目:(NOIP2004)虫食算 题解:见T4
T4:
难度:XXXX
题目:(NOIP2010)靶形数独 题解:见T4
T5:
难度:XXXX
题目:(NOIP2011)Mayan游戏 题解:见T3
简介:
该类DFS常用于子集型问题的搜索(也就是枚举子集的问题);
如果单纯DFS枚举子集,时间复杂度为:
但是双端DFS时间复杂度为:,这是一个比较巨大的优化
实现方法:
模板:
void dfs1(int i, ...){
if(i>n/2){
存入map或hash表;
return;
}
dfs1(i+1, ...);
dfs1(i+1, ...);
}
void dfs2(int i, ...){
if(i>n){
查找map或hash表,并与当前状态合并;
其他操作;
return;
}
dfs2(i+1, ...);
dfs2(i+1, ...);
}
例题讲解:
时间限制:1秒 内存限制:64M
【问题描述】
有重量和价值分别为wi,vi的n个物品。从这些物品中挑选总重量不超过W的物品,求所挑选方案中价值总和的最大值。
【输入格式】
第一行为整数n和W,分别表示物品数量和重量限制。接下来的n行,每行两个整数,表示一个物品的重量wi和价值vi。
【输出格式】
一个整数,表示最大价值。
【输入样例】
4 5
2 3
1 2
3 4
2 2
【输出样例】
7
【数据范围】
1<=n<=40 , 1<=wi,vi<=10^15 , 1<=W<=10^15
分析:
代码:
#include
#include
#include
#include
例题二:
难度:XXX+
注意啦:这个题目不再是子集枚举了,而是另一种双端搜索,也就是先从起点搜索状态,再从终点搜索状态直到相遇
(NOIP2002)字串变换(见T2)
拓展训练(题目推荐):
T1:
难度:XXX+
[USACO09NOV]灯Lights
注意:这道题子集枚举之前需要状态压缩,也就是将灯的状态用二进制方法表示,开关灯用异或(^)表示
简介: