C - Square Coins

 HDU - 1398 

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;
}