题意:把一个整数N(1 <= N <= 120)拆分不超过N的正整数相加,有多少种拆法。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1028
——>>经典题目呀,而且数据量不大。。。
设d[i][j]表示把整数i拆分成不过超过j的正整数和有拆法数,则
状态转移方程为:d[i][j] = d[i-j][j] + d[i][j-1];(大小细微处理一下)
递推式:
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 120 + 10;
int d[maxn][maxn];
void get(){
int i, j;
d[0][0] = 1;
for(i = 1; i <= 120; i++){
d[i][1] = d[0][i] = 1;
for(j = 1; j <= i; j++){
if(j <= i-j) d[i][j] = d[i-j][j] + d[i][j-1];
else d[i][j] = d[i-j][i-j] + d[i][j-1];
}
}
}
int main()
{
int N;
get();
while(scanf("%d", &N) == 1){
printf("%d\n", d[N][N]);
}
return 0;
}
记忆化搜索:
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 120 + 10;
int d[maxn][maxn];
int dp(int i, int j){
int& ans = d[i][j];
if(ans != -1) return ans;
if(i == 0 || j == 1) return ans = 1;
if(i - j >= 0){
if(j <= i-j) ans = dp(i-j, j) + dp(i, j-1);
else ans = dp(i-j, i-j) + dp(i, j-1);
}
else ans = dp(i, j-1);
return ans;
}
void get(){
int i;
memset(d, -1, sizeof(d));
for(i = 0; i < maxn; i++) d[i][1] = 1;
for(i = 1; i <= 120; i++) dp(i, i);
}
int main()
{
int N;
get();
while(scanf("%d", &N) == 1){
printf("%d\n", d[N][N]);
}
return 0;
}
做了道N很大的题目,要用公式计算,回想起这道题,也可以用公式做:
#include <cstdio>
using namespace std;
const int maxn = 120;
int p[maxn+10];
void init(){
int i, j, k, l, sum;
p[0] = 1;
for(i = 1; i <= maxn; i++){
sum = 0;
for(j = 1, k = 1, l = 1; j > 0; k++, l = -l){
j = i - (3*k*k - k) / 2;
if(j >= 0) sum += l * p[j];
j = i - (3*k*k + k) / 2;
if(j >= 0) sum += l * p[j];
}
p[i] = sum;
}
}
int main()
{
int N;
init();
while(scanf("%d", &N) == 1){
printf("%d\n", p[N]);
}
return 0;
}