四方定理 (dp,二维费用背包)

本文探讨了四方定理的解题思路,最初从位分解角度入手,但发现无法有效去重。后来意识到这是一个二维费用完全背包问题。问题中,不同平方数代表不同物品,每种平方数可无限次选取,消耗对应平方值的体积和1个分解位。通过完全背包动态规划可以解决去重问题,强调在遇到涉及选与不选、选多个的dp问题时,应考虑背包算法的应用。
摘要由CSDN通过智能技术生成

在这里插入图片描述

思路分析:

我一开始没往背包那想,我想的是dp[i][j]表示 i 值 剩余 j 次分解位的方案总数。
第一层 for 遍历 i 值 (1-32768)
第二层for 遍历 j 分解位个数 (0-4)
第三层for 遍历 k 平方数 (1-sqrt(i))
dp[i][j] = dp[i-k*k][j-1]
这样写理论上可以实现,但是无法去重。
假设i=5, j=1,k 可以取 1, 2. k取1就由dp[4][0]推来,k取2就由dp[1][0]推来。这样就包含了[1,2]和[2,1]两种情况。

后来看了题解才发现是一个二位费用完全背包问题。
多少个平方数就表示有多少种物品,给出的n表示背包容量。
每个平方数可选无限次,每个平方数 x 消耗 x*x 体积和 1 个分解位。
可以定义dp[i][j][k]表示前 i 种平方数,剩余总和 j,剩余选择 j 的方案总数。
dp[i][j][k] += dp[i-1][j-i*i][k-1]
通过完全背包可以除去 i 那一维。

经验:以后看dp,凡是看到决策涉及到选与不选,选多个这种题型都先往背包方向考虑一下。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

//当成二维费用完全背包问题
//有多少个平方数就表示有多少种物品,给出的n表示背包容量
//每个平方数可选无限次,每个平方数x消耗x*x体积和1个分解位

int main()
{
	int N = 32768;
	long long dp[32770][5]; //dp[j][k]表示剩余容量j,剩余分解位k的方案数
	memset(dp,0,sizeof(dp));
	for(int i = 0;i <= 4;i++) dp[0][i] = 1; //容量为0时每个剩余分解位的方案数都考虑进去 
	for(int i = 1;i*i <= N;i++) //因为平方数按顺序遍历,所以自然就去重了
	{
		for(int j = i*i;j <= N;j++)
		{
			for(int k = 1;k <= 4;k++)
			{
				dp[j][k] += dp[j-i*i][k-1];
			}
		}
	}
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n;
		scanf("%d",&n);
		printf("%lld\n",dp[n][4]);
	}
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值