递推与递归分析


递推与递归

递推和递归算是dp的基础入门题

递推的本质在于找规律从结论出发递推,确定初始值变可以通过自底向上递推

递归则是确定边界条件先自顶向下 → \rightarrow 自底向上

p1255 数楼梯

题目描述

楼梯有 N 阶,上楼可以一步上一阶,也可以一步上二阶。

编一个程序,计算共有多少种不同的走法。

输入格式

一个数字,楼梯数。

输出格式

输出走的方式总数。

分析:

​ 递推公式研究,一次又两种走法:一步一阶,一步两阶

当走到第n阶时又f[n]个走法,n阶可以通过从n-1阶走一步实现,和从n-2阶走两步实现

同样重要的还有设置初值: f[1] = 1, f[2] = 2 ,

第一个台阶有1种走法 第二个台阶有2种走法
f [ n ] = { f [ n − 1 ] + f [ n − 2 ] , n > 2 2 , n = 2 1 , n = 1 f[n]= \begin{cases} f[n-1]+f[n-2],& \text{n > 2} \\ 2, & \text{n = 2} \\1, & \text{n = 1} \end{cases} f[n]=f[n1]+f[n2],2,1,n > 2n = 2n = 1

#include<bits/stdc++.h>
using namespace std;
const int N = 1000010;
int f[N];
int main()
{
    int n;
    cin >> n;
    f[1] = 1, f[2] = 2;
    for(int i = 3; i <= n; i++)
        f[i] = f[i-1] + f[i-2];
   	cout << f[n];
    return 0;
}

P1036 [NOIP普及] 选数

题目描述

已知 n 个整数 x_1,x_2,…,x_n 以及1个整数k(k<n)。从n个整数中任选k个整数相加,可分别得到一系列的和。 例如当 n = 4 , k = 3, 4个整数分别为3, 7, 12, 19时,可得全部的组合与它们的和为:

3+7+12=22

3+7+19=29

7+12+19=38

3+12+19=34

现在,要求你计算出和为素数共有多少种。

例如上例,只有一种的和为素数:3+7+19=29。

输入格式

键盘输入,格式为:

n,k(1≤ n ≤20, k < n)

x_1,x_2,…,x_n

输出格式

屏幕输出,格式为: 1个整数(满足条件的种数)。

输入输出样例

输入 #1

4 3
3 7 12 19

输出 #1

1

分析

  • 筛选素数模板
  • 从n个数中选取k个数的模板(此题为不降原则去重)

筛选素数

  1. 试除法判定质数 O ( n ) O(\sqrt{n}) O(n )
bool isPrime(int n)
{
    if(n < 2)	return false;
    for(int i = 2; i <= n/i; i++)		//不建议用sqrt(n) 调用整个函数比较慢
	{
		if(n %i == 0)
			return false;
	}
	return true;
}

Cn的组合问题

​ 组合就是从n个元素中抽出k个元素一共有多少种不同组合

  • 不需要去重
#include<bits/stdc++.h>
using namespace std;
#define N 100010
int n, k;
int a[N];
int book[N];
/**
	自己画一个决策树就明白了
*/
void dfs(int cur)
{
	if(cur == k)
	{
		for(int i = 0; i < k; i++)
			printf("%d ", a[i]);
		printf("\n");
		return;	
	}

	for(int i = 1; i <= n; i++)
	{
		if(book[i] == 0)
		{
			a[cur] = i;
			book[i] = 1;
			dfs(cur+1);
			book[i] = 0;
			
		}
	}
	
	return;
}
 
int main()
{
	
	cin >> n >> k;
	dfs(0);
	
	return 0;
}

  • 需要去重采取不降原则

    采取不降原则的时候就不需要book[]数组判重了

include<bits/stdc++.h>
using namespace std;
int n, r, a[21];
void dfs(int start, int cur)
{
	if(cur == r)				//cur == r 时表示已经从n个数里面选出r个数 数组a[] 0~n-1已经选完数了
	{
		for(int i = 0; i < r; i++)
		{
			printf("%3d", a[i]);
		}
		printf("\n");
		return;
	}
	for(int i = start; i <= n; i++)			//n次循环表示从n个数里面选  cur表示已经选的个数 (并且采用上一题的不降原则 ) 
	{
		a[cur] = i;
		dfs(i+1, cur+1);		//下一层start当前数+1	cur+1表示放下一个位置
	}
	
}
int main()
{
	cin >> n >> r;
	dfs(1,0); 
	return 0;
 } 

答案

​ 采取的是不降模板

#include<bits/stdc++.h>
using namespace std;
#define N 100010
int n, k, ans;
int a[N];
bool isPrime(int n)
{
    for(int i = 2; i <= sqrt(m); i++)
	{
		if(m %i == 0)
			return 0;
	}
	return 1;
}
//多了一个参数sum是因为他最后要求组合数的和 可以在递归的时候传递,不然最后还有遍历
void dfs(int start, int cur, int sum)
{
    if(cur == k)
    {
        if(isPrime(sum))
            ans++;
    }
    for(int i = start; i <= n; i++)
    {
        dfs(i+1,cur+1,sum+a[i]);
    }
}

int main()
{
    cin >> n >> k;
    for(int i = 0; i < n; i++)
        cin >> a[i];
        
    dfs(1,0,0)
    cout << ans;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值