【简单dp】最少的双重平方数来组成n

178 阅读1分钟

题目描述

给你一个正整数n,现规定n只能由双重平方数相加得到,请你找到最少的双重平方数来组成n。例如,n=17n=1717=14+2417=1^4+2^4,没有更少的双重平方数可以相加组成17,则答案是2。

输入

输入一行,一个正整数n(0<n1050<n\le10^5

输出

输出一行,包括一个整数表示最少需要的双重平方数个数。

样例输入

17

样例输出

2

思路

首先发现题目中n最大是10510^5,而此范围内最大的双重平方数为174=8352117^4=83521184=10497618^4=104976),所以可以先求出来前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";
    
}

例如当n2464124641时,答案应该是2224641=10000+14641=104+11424641=10000+14641=10^4+11^4。但是,如果是贪心的思路,那么每次取最大,那么就会得到:24641=20736+2401+1296+81+81+16+16+1+1+1+1+1+1+1+1+1+1+1+1+1+1=124+74+64+2×34+2×24+1424641=20736+2401+1296+81+81+16+16+1+1+1+1+1+1+1+1+1+1+1+1+1+1=12^4+7^4+6^4+2\times 3^4+2\times 2^4+14,显然,这个结果是错的。

使用动态规划解决本题。

动态规划

  1. dp[x]表示组成x需要使用的最少的四次方数的个数
  2. 状态转移方程d[x+i^4]=min{d[x+i^4],d[x]+1}
  3. 初始化:d[a[i]]=1;其他为i
  4. 遍历顺序:从前到后
  5. 举例,符合条件

代码

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