hdu1028 Ignatius and the Princess III ——DP

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1028

题目大意: 

  整数拆分,给一个整数n,求它有多少种拆分方法。

题目思路:

做法一:

  d[i][j]表示把整数 i 拆成最多 j 个数字所具有的方法数。那么

  if (i >j) d[i][j] = d[i-j][j] + d[i][j-1]; 意思就是如果i>j,那么有两种方式:一种是先把i里面分理处j个1,然后再把i-j拆成最多i-j个数字;另一种是把i拆分成最多j-1个数字。

  if (i < j) d[i][j] = d[i][i]; 意思就是如果i<j,那么这种情况和把数字i最多拆成i个数字的是一样的。

  if (i == j) d[i][j] = d[i][j-1] + 1; 意思就是如果i==j,那么可以把数字i拆分成j-1个数字,也可以把数字i拆分成i个1(这个就是那个1的意义)

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <cstring>
 5 using namespace std;
 6 #define LL long long
 7 int d[140][140], n;
 8 void init() {
 9   while (~scanf("%d", &n)) {
10     int i, j; memset(d, 0, sizeof(d));
11     for  (i = 0; i <= n; ++i) d[i][1] = d[1][i] = 1;
12     for (i = 2; i <= n; ++i) {
13       for (j = 1; j <= n; ++j) {
14         if (i > j) d[i][j] = d[i-j][j] + d[i][j-1];
15         else if (i == j) d[i][j] = 1 + d[i][j-1];
16         else d[i][j] = d[i][i];
17       }
18     }
19     cout << d[n][n] << endl;
20   }
21 }
22 int main(void) {
23   init();
24   return 0 ;
25 }

  剩下的就是考虑一下边界,比如当 i 或者 j 等于1的时候,显然都是只有一种拆分情况。

做法二:

  借用hdu1284这道题的方法,也可以做这道题目,因为n的范围是120嘛,两个算法的复杂度都是O(n^2)的,当然可以了。只需要把hdu1284的代码里面把3改成n,这题就过了……

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <cstring>
 4 const int MAX = 32768+10;
 5 long long d[MAX];
 6 void solve() {
 7   int n, i, j;
 8   while (~scanf("%d", &n)) {
 9     memset(d, 0, sizeof(d));
10     d[0] = 1;
11     for (i = 1; i <= n; ++i) {
12       for (j = i; j <= n; ++j) {
13         d[j] += d[j-i];
14       }
15     }
16     printf("%lld\n", d[n]);
17   }
18 }
19 int main(void) {
20   solve();
21   return 0;
22 }

优化到了一维数组,这个方法碉堡了……

参考博客:http://www.cnblogs.com/qiufeihai/archive/2012/09/11/2680840.html 膜拜……

原文地址:https://www.cnblogs.com/liuxueyang/p/3095437.html