HDU 1028

题目大意:

给一个数n,求出这个数的不重复整数排列。

解题思路:

(1)递归求解:栈深度有点高,可以通过记忆+剪枝优化。

(2)初始化二维数组dp,dp[i][j],表示当前输入的数字为i时,排列的第一个数字为j时有几种排列方法。

不难看出

1可以拆分成1+0,只有1种

2可以拆分成2+0,1+1两种。

3可以拆分成3+0,2+1,1+1+1,三种

4可以拆分成4+0,3+1,2+2,2+1+1,1+1+1+1,五种。

。。。。。。

以n=4为例,

4 = 4 + 0

4 = 3 + 1

4 = 2 + 2 

4 = 2 +1 + 1

4 = 1 + 1 + 1 + 1

从上面可以看出,我们把第一个数字和后面的所有数字分开看,第一个数字最大,第二个其次,第三个依次和前面一样,相等或减小。一直到1 或 0 为止。这样递归就很明显了,这里用第二种方法求解,我们设dp数组,它的意义和上面说的一样。

(1)首先初始化dp数组。当第一个数字是1的时候,后面肯定都是1.这样dp[i][1] = 1;就确定了。

当第一个数字是n时,那么n = n + 0,也只有1种,所以dp[i][i] = 1也是确定的,同理,当 n = n-1时,后面那个1不可再分,也只能是1中,

这样初始化工作完成。

(2)初始化完成之后,我们分析一下规律。

我们先把n分成两个数字a和b,a从n到1递减,b=n-a,那么就有两种情况:

1.a >= b 

2 a < b 

情况1:当a >= b 时,我们直接计算sums(b)即可,这个sums(b,b)的值就是当总和为n的时候,第一个数字是a的排列种数。sums(x,y)函数定义:当n= x时,第一个数字从1到y的所有可能种类数的和。也就是从dp[x][1]一直加到dp[x][y],设立这个函数是必要性可以看情况2.

情况2:当 a < b 时, 就是说第一个数字小于第二个数字,那么如何让这样的情况也符合条件呢,那么就让第二个数字b拆分,拆分成a和b-a两个数字,这样第2个数字就小于等于第一个数字了,比如说:5 = 2 + 3 = 2 + 2 + 1,这样我们调用sums函数传参为sums(3,2),也就是说计算总和n=3,但是第一个拆分数字小于等于2的情况一共有多少种。也就是说对于这个n=5的例子中,以2为第一个数字的情况种数就等于3的以小于等于2为第一个数字的情况数之和。

综上所述,没输入一个数字n,就直接输出sums(n,n),就可以算出题目结果。测试AC代码如下

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<string>
 5 using namespace std;
 6 const int N = 124;
 7 int dp[N][N];
 8 
 9 int res = 0;
10 
11 int sums(int b,int a){
12     int res = 0 ;
13     for(int i = 1 ; i<= a; ++i){
14         res += dp[b][i];
15     }
16     return res;
17 }
18 void init(){
19     memset(dp,0,sizeof(dp));
20     for(int i = 0 ;i < N ; ++i){
21         dp[i][1] = 1;
22         dp[i][i] = 1;
23         dp[i][i-1] = 1;
24     }
25     for(int i = 3 ;i < 121; ++i){
26         for(int j = 2; j < i - 1; ++j){
27             int n = i , a = j, b = i - j;
28             if(a >= b){
29                 dp[i][j] = sums(b,b);
30             }else{
31                 dp[i][j] += sums(b,a);
32             }
33         }
34     }
35 }
36 
37 int main(){
38     int n;
39     init();
40     while(cin>>n){
41         cout<<sums(n,n)<<endl;
42     }
43     return 0 ;
44 }

 

posted @ 2018-01-04 19:56  砂糖橘子君  阅读(187)  评论(0编辑  收藏  举报