算法设计与分析—分治 Ignatius and the Princess III (整数划分)

先补充一点小知识,看到下面的知识写的很好:

分治法的基本思想:将一个规模为n的问题分解为k个规模较小的子问题,这些子问题互相独立且与原问题相同。递归地解这些问题,然后将各个子问题的解合并成原问题的解。
分治法所能解决的问题一般具有以下几个特征:

该问题的规模缩小到一定的程度就可以容易地解决;因为问题的计算复杂性一般是随着问题规模的增加而增加,因此大部分问题满足这个特征。

该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质这条特征是应用分治法的前提,它也是大多数问题可以满足的,此特征反映了递归思想的应用

利用该问题分解出的子问题的解可以合并为该问题的解;能否利用分治法完全取决于问题是否具有这条特征,如果具备了前两条特征,而不具备第三条特征,则可以考虑贪心算法或动态规划。

该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。这条特征涉及到分治法的效率,如果各子问题是不独立的,则分治法要做许多不必要的工作,重复地解公共的子问题,此时虽然也可用分治法,但一般用动态规划较好(例如记忆化搜索是分治转化为动归的一个经典)。

“Well, it seems the first problem is too easy. I will let you know how foolish you are later.” feng5166 says.

“The second problem is, given an positive integer N, we define an equation like this:
N=a[1]+a[2]+a[3]+…+a[m];
a[i]>0,1<=m<=N;
My question is how many different equations you can find for a given N.
For example, assume N is 4, we can find:
4 = 4;
4 = 3 + 1;
4 = 2 + 2;
4 = 2 + 1 + 1;
4 = 1 + 1 + 1 + 1;

so the result is 5 when N is 4. Note that “4 = 3 + 1” and “4 = 1 + 3” is the same in this problem. Now, you do it!”

Input
The input contains several test cases. Each test case contains a positive integer N(1<=N<=120) which is mentioned above. The input is terminated by the end of file.

Output
For each test case, you have to output a line contains an integer P which indicate the different equations you have found.

Sample Input
4
10
20

Sample Output
5
42
627

故事还是那个故事,第一个问题人家答出来了还不能接公主走,还要答第二个,魔兽就是魔兽啊!
这次问题高级太多了,整数划分问题。输入第一行是整数,输出是这个整数有多少划分。
上来啥也不说一通递归 如下 ↓

#include <iostream>
using namespace std;
int spilt(int n,int m){
	if(n==1||m==1)
		return 1;
	else if(n<m)
		return spilt(n,n);
	else if(n==m)
		return spilt(n,m-1)+1;
	else
		return spilt(n,m-1)+spilt(n-m,m);
}
int main(){
	int n;
	while(cin>>n){
		cout<<spilt(n,n)<<endl;
	}
	return 0;
} 

所谓分治,分而治之。这个函数有两个变量,n是我们所求,m是小于n的数。n是我们所求,m代表最大加数不大于m的划分数。什么意思呢?举例来说,n是4,即求4的整数划分时,m可在递归过程中依次取4,3,2,1。当然了,如果m大于n,递归时会将m变为n。下面依次看递归条件:
①n等于1时划分数自然只有1,而m=1是递归的边界条件,即已经到了不大于1的加数的划分,自然也只有一个;
②n<m时将m变为n;
③n等于m时,自然只有一个是本身,所以先加上1,然后m-1遍历;
④n>m>1时,要加上m的整数划分,和m-1的整数划分。
很好,变得很简洁。但!
超时了!哎呀怎么超时了呢……递归时间复杂度太高了
所以搜索了一下用动态规划……并且,用cin cout还re了,要用scanf printf。

#include<iostream>  
using namespace std;  
int dp[121][121];  
int solve(int n){  
    for(int i=1;i<=n;i++)
		dp[0][i]=1;  
    for (int i=1;i<=n;i++){  
        dp[i][0]=0;  
        for(int j=1;j<=n;j++){ 
            if(i<j)   
                dp[i][j]=dp[i][i];  
            else  
                dp[i][j]=(dp[i-j][j]+dp[i][j-1]); 
		}
    }  
    return dp[n][n];  
}  
int main() {  
    int n,ans;  
    while(cin>>n){  
        cout<<solve(n)<<endl;    
    }  
    return 0;  
}  

用二维数组来存,把

发布了37 篇原创文章 · 获赞 0 · 访问量 379

猜你喜欢

转载自blog.csdn.net/weixin_45351699/article/details/104738080