C - Square Coins
People in Silverland use square coins. Not only they have square shapes but also their values are square numbers. Coins with values of all square numbers up to 289 (=17^2), i.e., 1-credit coins, 4-credit coins, 9-credit coins, ..., and 289-credit coins, are available in Silverland.
There are four combinations of coins to pay ten credits:
ten 1-credit coins,
one 4-credit coin and six 1-credit coins,
two 4-credit coins and two 1-credit coins, and
one 9-credit coin and one 1-credit coin.
Your mission is to count the number of ways to pay a given amount using coins of Silverland.
Input
The input consists of lines each containing an integer meaning an amount to be paid, followed by a line containing a zero. You may assume that all the amounts are positive and less than 300.
Output
For each of the given amount, one line containing a single integer representing the number of combinations of coins should be output. No other characters should appear in the output.
Sample Input
2
10
30
0
Sample Output
1
4
27
题目大意,给出1-17的17个整数的平方,作为基本硬币,分别为 1,4,9,16....256,289
给定一个数字,要求给出组合方式的总数,如 10 可以拆成
10个1
2个4和2个2
1个4和6个1
1个9和1个1
共4种
思路:
1.完全背包问题:
根据有向无环图进行计数,将重复计算的值进行保存,其中每一层表示对应的硬币,通过
取这一层的 0 个 、1个、2个。。将这一层进行遍历,然后再向下一层,
每一层表示一个币种,当其中出现num == 0时,表示已经拼凑完了,可以返回结果。
还是类似有向无环图的思路,查找最大值。
code:
#include<iostream>
#include<cstdio>
#include<cstring>
typedef long long ll;
using namespace std;
//所有硬币
int arr[18];
//dp 保存第几层,以及剩下的当前值
int dp[19][305];
int N;
void init(){
for(int i=1;i<=17;i++){
arr[i] = i*i;
}
memset(dp,-1,sizeof(dp));
}
ll dfs(int dep,int num){
//如果已经存在了,则直接返回
if(dp[dep][num]!=-1) return dp[dep][num];
//如果值全减掉了,说明这次拼凑是成立的
if(num == 0) return dp[dep][num] = 1;
//如果便利完所有的硬币之后,依然没有 == 0 则是不成立的,返回0
if(dep==18) return dp[dep][num] = 0;
ll ans=0;
//计算答案,求和
for(int i=0;num>=i*arr[dep] ;i++){
ans+=dfs(dep+1,num -arr[dep]*i);
}
//返回答案并记录
return dp[dep][num] = ans;
}
int main(){
init();
while(scanf("%d",&N)!=EOF){
if(N == 0) break;
ll ans = dfs(1,N);
printf("%lld\n",ans);
}
return 0;
}