倒计时日历151天 P1036 熙熙爸的信息奥赛 深度优先搜索 DFS
深度优先搜索(Depth First Search缩写为DFS)属于图算法的一种,其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次。
DFS基于递归思想,通过递归的形式来缩小问题规模,把一件事分割成若干个相同的小事,逐步完成。
深度优先搜索的步骤分为 1.递归下去 2.回溯上来。顾名思义,深度优先,则是以深度为准则,先一条路走到底,直到达到目标。这里称之为递归下去。
否则既没有达到目标又无路可走了,那么则退回到上一步的状态,走其他路。这便是回溯上来。
从N个数中选取k个数的组合–不降原则(DFS):不降原则举个例子:比如说在6里面随便选5个数,那么选法都是什么呢?瞎枚举?1234512346前两个还不会弄混然后很可能就乱了少点数可能不会乱但是多了就不好整了比如说在100里随便选50个数。1 2 3 4 5 6 7 8 9 10 11 12…所以我们可以运用不降原则:保证枚举的这些数是升序排列其实真正的不降原则还可以平1 2 2 3 3 4…但是这里要说的“不降原则”不能平哦!对于这道题也不能平否则就有重复数字了拿6个里面选3个举例子1 2 31 2 41 2 51 2 6第一轮枚举完毕。第二个数加一1 3 ?这个“?”应该是4,因为是升序排列1 3 41 3 51 3 6接着,就是这样1 4 51 4 61 5 6第一位是1枚举完毕第一位是2呢?2 3 42 3 52 3 62 4 52 4 62 5 6就是这样的,枚举十分清晰,对吗?以此类推…3 4 53 4 63 5 64 5 6然后就枚举不了了,结束。所以说,这样就可以避免判重了。
深度优先搜索的模板:
void dfs()//参数用来表示状态
{
if(到达终点状态)
{
...//根据题意来添加
return;
}
if(越界或者是不符合法状态)//剪枝
return;
for(扩展方式)
{
if(扩展方式所达到状态合法)
{
....//根据题意来添加
标记;
dfs();
修改(剪枝);
(还原标记);
//是否还原标记根据题意
//如果加上(还原标记)就是 回溯法
}
}
}
P1036 题目描述
已知
现在,要求你计算出和为素数共有多少种。
例如上例,只有一种的和为素数:
输出格式
屏幕输出,格式为:
输入
4 3
3 7 12 19
输出
1
【题目来源】
NOIP 2002 普及组第二题
using namespace std;int n,k,x[20];bool isPrimeNumber(int nNumber){for(int i = 2; i * i <= nNumber; i++)if(nNumber % i == 0)return false;return true;}int dfs(int nNeedToChoose, int nChooseSum, int nStart, int nEnd){if(0==nNeedToChoose){return isPrimeNumber(nChooseSum);}int sum=0;for(int i=nStart;i<=nEnd;i++){sum += dfs(nNeedToChoose-1, nChooseSum+x[i], i+1, nEnd);}return sum;}int main(){cin>>n>>k;for(int i=0;i<n;i++)cin>>x[i];cout<<dfs(k,0,0,n-1);return 0;}
喜欢这篇文章就点这里
