题目大意:给出一个价值N的货品,有300种货币,价值分别为1-300,可能会给出L1和L2,当给出的只有N的时候,要求你求出用N个货币表示价值为N的货品有几种方法,当给出的只有N和L1的时候,要求你给出用1到L1个货币表示价值为N的商品有多少种表示方法,当给出N,L1,L2时,要求你给出用L1到L2个货币能表示价值为N的货品有多少种方法
解题思路:解法1.看Staginner大神的,如果不理解的话,请看点击打开链接,用dp[i][j]表示价值为i的用面值最大为j的货币表示有多少种方法,假设不用j这个货币,则dp[i][j] = dp[i][j-1],如果用了j这个货币,则dp[i][j] = dp[i-j][j],所以dp[i][j] = dp[i-j][j] + dp[i][j-1]
解法2:用dp[i][j]表示用j个货币能组成价值为i的商品有多少种组合方法,则dp[i][j] = dp[i][j] + dp[i-k][j-1] ,这就相当于01背包问题了,初始化dp[0][0] = 1
解法1代码
#include<cstdio>
#include<cstring>
#define maxn 305
int N,L1,L2,count;
char str[100];
long long dp[maxn][maxn];
void init() {
memset(dp,0,sizeof(dp));
dp[0][0] = 1;
for(int i = 0 ; i <= 300; i++)
for(int j = 1; j <= 300; j++){
if(i - j >= 0)
dp[i][j] += dp[i-j][j];
if(j - 1 >= 0)
dp[i][j] += dp[i][j-1];
}
}
int main() {
init();
while(gets(str)) {
int flag = sscanf(str,"%d%d%d",&N,&L1,&L2);
L1 = L1 > 300 ? 300:L1;
L2 = L2 > 300 ? 300:L2;
if(flag == 1)
printf("%lld\n",dp[N][N]);
else if(flag == 2)
printf("%lld\n",dp[N][L1]);
else if(flag == 3 && L1 == 0)
printf("%lld\n",dp[N][L2]);
else if(flag == 3 && L1 > 0)
printf("%lld\n",dp[N][L2] - dp[N][L1-1]);
}
return 0;
}
解法2代码:
#include<cstdio>
#include<cstring>
#define maxn 305
long long dp[maxn][maxn];
char str[100];
int N,L1,L2;
void init() {
int n = 300;
memset(dp,0,sizeof(dp));
dp[0][0] = 1;
for(int i = 1; i <= n; i++)
for(int j = i; j <= n; j++)
for(int k = 1; k <= n; k++)
dp[j][k] += dp[j-i][k-1];
}
int main(){
init();
while(gets(str)) {
int flag = sscanf(str,"%d%d%d",&N,&L1,&L2);
L1 = L1 > 300 ? 300:L1;
L2 = L2 > 300 ? 300:L2;
long long sum = 0;
if(flag == 1)
for(int i = 0; i <= N; i++)
sum += dp[N][i];
else if(flag == 2)
for(int i = 0 ; i <= L1; i++)
sum += dp[N][i];
else if(flag == 3)
for(int i = L1; i <= L2; i++)
sum += dp[N][i];
printf("%lld\n",sum);
}
return 0;
}