本文主要是介绍寒假之(递归与分治),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
递归的思想就把问题简单化,分为更小的子问题,一个一个去解决,每种情况之间还会回溯,分出所有的情况,对于一些数据量小的问题,可以用全递归,对于数据量大的,就可以用DP(记忆化搜索)(现在不提)。穷尽搜索时可以考虑递归算法。具有一定的回退性。
分治与递归是分不开的,将问题分为局部问题。递归求解局部为。将局部问题”整合“,解决原问题。
看道题目:
编写一个程序,读取n个元素和整数m的序列a,如果可以通过在a中添加元素来生成m,则输出“yes”,否则输出“no”。一个元素只能使用一次。
在每个问题中都包含mi的顺序A和Q问题。
输入
在第一行给出n。在第二行中,给出n个整数。第三行中给出了q。然后,在第四行中,给出q整数(mi)。
输出
对于每个问题mi,打印“是”或“否”
Constraints
- n ≤ 20
- q ≤ 200
- 1 ≤ elements in A ≤ 2000
- 1 ≤ Mi ≤ 2000
Sample Input 1
5
1 5 7 10 21
8
2 4 17 8 22 21 100 35
Sample Output 1
no
no
yes
yes
yes
yes
no
no
首先看题,不知道怎么下手,怎么用循环把所有的情况列举出来,再来判断?有点困难,题解用递归实现穷举,将情况全部都判断一遍,递归有个好处,可以回溯返回上一层的情况,接着改变状态,再判断一次,看看能否满足条件。第一个数列的每个数据都有两种状态,可以选,也可以不选。于是,递归的这个方程就是将所有情况都考虑进去,就可以实现穷举所有情况。(需要将所有情况都考虑进去)。
如果选择当前数据,就 当前的满足条件的和(每次递归都会不一样的,状态不一样,类似于状态转移方程,每次的状态都会改变)。
代码就会出来:
#include<stdio.h>
#include<iostream>
using namespace std;
#include<string>
#include<string.h>
#include<algorithm>
#include<queue>
#include<vector>
#include<list>
#include<set>
const int maxn=100005;
typedef long long ll;
int n;
int a[maxn];
int solve(int i,int m){if(m==0)return 1;if(i>=n)return 0;int res=solve(i+1,m)||solve(i+1,m-a[i]);return res;}
int main()
{int q,m,i;cin>>n;for(i=0;i<n;i++)cin>>a[i];cin>>q;for(i=0;i<q;i++){cin>>m;if(solve(0,m))cout<<"yes"<<endl;elsecout<<"no"<<endl;}return 0;
}
用1来表示被选中,0表示没被选中。solve(i+1,m) || solve(i+1,m-a[i]) 是两种状态,可以选,也可不选,穷尽搜索将所有情况考虑进去。
放苹果 POJ 1664
Description
把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。
Input
第一行是测试数据的数目t(0 <= t <= 20)。以下每行均包含二个整数M和N,以空格分开。1<=M,N<=10。
Output
对输入的每组数据M和N,用一行输出相应的K。
Sample Input
17 3
Sample Output
8
同样采取 递归穷尽搜索的方法,来得到所有的可能, 这就需要将所有的分的方法都要想到,大致可以分为 1.至少有一个空盘子 2.没有空盘子。如果盘子数量大于苹果的数量,就可以把多余的盘子扔掉(因为没有用)。思路大概是这个样子。 第一种情况,可以有盘子为空的情况,那就在别的盘里面多放几个,盘子数量减减,直到盘子就为一个的时候,这就到达终点了,将所有苹果全放到这一个盘子里面。2.第二种情况就是,没有盘子为空的,所有盘子都有苹果,那就把余下的苹果再按照这几个盘子再去分,就会达到每个盘子数量不一样的情况,直到分的苹果最后为0 的时候,说明苹果一遍一遍的 以一个为单位放到每个盘子情况结束。
因为递归有回溯的功能,这两种情况会不断地重叠,交叉,来达到穷举的效果。
想到这里,代码基本上就会出来了:
代码:
#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
const int maxn=1000100;
using namespace std;
typedef long long ll;
const int mod=1000000000;
ll fun(ll m,ll n)
{if(m==0||n==1) return 1;if(m<n)fun(m,m); elsereturn fun(m,n-1)+fun(m-n,n);
}
int main()
{int t;cin>>t;ll m,n;while(t--){cin>>m>>n;cout<<fun(m,n)<<endl;}return 0;
}
基本上的思想就是这样子。但是分治与递归的题型会很多。就在训练题中一个一个遇见吧。
递归与分治练习题目 HDU 4643 2050 POJ 2586
这篇关于寒假之(递归与分治)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!