题目大意:求出将给定数字分成若干正整数的不同方法个数
题目分析:该题可等价转化为硬币转化问题:有各种正整数面值的硬币,求出给定钱数的不同组合方式的个数,定义dp(x,y)为能组成x元的,且最大面值为coin[y]的不同组合方式。状态转移方程为:dp(x,y) = dp(x-coin[y],y)+dp(x,y-1);
则答案只需要从最大的y开始往前扫,第一个不为零的dp(x,y)即为答案。
代码如下:
#include <iostream>
#include <stdio.h>
#include <fstream>
#include <iomanip>
#include <cmath>
#include <string>
#include <string.h>
#include <sstream>
#include <cctype>
#include <climits>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <iterator>
#include <algorithm>
#include <stack>
#include <functional>
/*int类型最大值INT_MAX,short最大值为SHORT_MAX
long long最大值为LONG_LONG_MAX*/
//cout << "OK" << endl;
#define _clr(x) memset(x,0,sizeof(x))
using namespace std;
const int INF = INT_MAX;
const double eps = 1e-8;
const double EULER = 0.577215664901532860;
const double PI = 3.1415926535897932384626;
const double E = 2.71828182845904523536028;
typedef long long LL;
//const int coin[5] = {1,5,10,25,50};
int res[150][150] = {0};
int dp(int x,int y)
{
if(res[x][y]) return res[x][y];
int ans = 0;
for(int j = y;j>=1;j--)
{
if(x<j) continue;
ans+=dp(x-j,j);
}
return res[x][y] = ans;
}
int main()
{
//freopen("sample.in", "r", stdin);
//freopen("sample.out", "w", stdout);
for(int j = 120;j>=0;j--) res[0][j] = 1;
for(int i = 1;i<=120;i++)
for(int j = 120;j>=1;j--)
{
if(i<j) continue;
res[i][j] = dp(i,j);
}
int n;
while(cin >> n)
for(int j = 120;j>=1;j--)
if(res[n][j])
{
cout << res[n][j] << endl;
break;
}
//fclose(stdin);
//fclose(stdout);
return 0;
}