题目描述
给你一个正整数n,现规定n只能由双重平方数相加得到,请你找到最少的双重平方数来组成n。例如,,,没有更少的双重平方数可以相加组成17,则答案是2。
输入
输入一行,一个正整数n()
输出
输出一行,包括一个整数表示最少需要的双重平方数个数。
样例输入
17
样例输出
2
思路
首先发现题目中n最大是,而此范围内最大的双重平方数为(),所以可以先求出来前18个数的双重平方数。
我一开始想的是贪心,每次把最大的双重平方数凑上去,但是发现思路是错的:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int a[19],n;
int *it;
int ans=0;
int main()
{
for(int i=1;i<=18;i++) a[i]=(i*i*i*i);
cin>>n;
// for(int i=1;i<=18;i++) cout<<a[i]<<"\n";
// cout<<lower_bound(a,a+19,81)-a<<"\n";
while(n){
ans++;
it=lower_bound(a,a+19,n);
if(n==(*it)) n-=(*it);
else n-=(*(it-1));
// cout<<n<<" -\n";
}
cout<<ans<<"\n";
}
例如当n是时,答案应该是:。但是,如果是贪心的思路,那么每次取最大,那么就会得到:,显然,这个结果是错的。
使用动态规划解决本题。
动态规划
dp[x]表示组成x需要使用的最少的四次方数的个数- 状态转移方程
d[x+i^4]=min{d[x+i^4],d[x]+1} - 初始化:
d[a[i]]=1;其他为i - 遍历顺序:从前到后
- 举例,符合条件
代码
#include <iostream>
#include <cstring>
#include <algorithm>
const int N = 2e5+10;
using namespace std;
int a[18],dp[N];
int n;
int main()
{
cin>>n;
for(int i=1;i<=n;i++) dp[i]=i;
for(int i=1;i<=18;i++){
a[i]=(i*i*i*i);
dp[a[i]]=1;
}
for(int i=1;i<=n;i++)
for(int j=1;i+a[j]<=n;j++)
dp[i+a[j]]=min(dp[i+a[j]],dp[i]+1);
cout<<dp[n];
}