1 条题解
-
0
自动搬运
来自洛谷,原作者为

easy42
无蓝钩不改签搬运于
2025-08-24 23:05:41,当前版本为作者最后更新于2024-11-04 17:46:50,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
清新的动态规划。
易列出状态转移方程
dp[i] = min(dp[i], dp[i - j * j] + 1)。解释在下面:
状态转移方程的含义
- 状态转移方程
dp[i] = min(dp[i], dp[i - j * j] + 1)(其中j * j <= i)的含义是在计算总和为i的完全平方数的最小数量dp[i]时,考虑使用小于等于i的完全平方数j * j来构建i。 dp[i - j * j]表示已经计算出的总和为i - j * j的完全平方数的最小数量。通过加上一个完全平方数j * j,就可以得到总和为i的一种拆分方式,其数量为dp[i - j * j] + 1(因为多使用了一个完全平方数j * j)。- 对于每个
i,我们尝试所有可能的完全平方数j * j(只要j * j <= i),并从这些可能的拆分方式中选择数量最少的,即取min(dp[i], dp[i - j * j] + 1)。这样不断更新dp[i],最终得到总和为i的完全平方数的最小数量。
例如,当计算
dp[5]时:- 首先
j = 1,j * j = 1,dp[5 - 1] = dp[4],假设dp[4]之前已经计算为1(因为4 = 4本身就是一个完全平方数,数量为1),那么dp[5]就会更新为min(dp[5], dp[4] + 1) = min(初始值, 1 + 1) = 2。 - 然后
j = 2,j * j = 4,dp[5 - 4] = dp[1],dp[1]初始为1(因为1 = 1),此时dp[5]会再次更新为min(dp[5], dp[1] + 1) = min(2, 1 + 1) = 2(因为2更小)。 - 继续
j = 3,j * j = 9,但9 > 5,循环结束,dp[5]最终为2,表示5可以拆分为1 + 4,使用了两个完全平方数,这是最少的拆分数量。
代码:
#include <iostream> #include <cmath> using namespace std; int main() { int n; cin >> n; int dp[n + 1]; for (int i = 0; i <= n; i++) { dp[i] = i; // 初始化,最坏情况就是全是1相加 } for (int i = 1; i <= n; i++) { for (int j = 1; j * j <= i; j++) { dp[i] = min(dp[i], dp[i - j * j] + 1); } } cout << dp[n] << endl; return 0; }可以的话,能不能点个关注和赞?
- 状态转移方程
- 1
信息
- ID
- 10803
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 2
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者