砝码称重

一、题目描述

P8742 [蓝桥杯 2021 省 AB] 砝码称重

二、问题简析

类似 01背包,对于每个元素,可以拿(+-)或不拿。
\(dp[i + 1][j]=\) \(i + 1\) 个元素是否可以使值为 \(j\)

\[dp[i + 1][j] = \begin{cases} true &,dp[i][j]~or~dp[i][j - A[i]]~or~dp[i][j + A[i]] ==true \\ false &,others \end{cases} \]

注:

  • 1、\(dp[i][j - A[i]]\) 代表 + 这个元素。显然,j - A[i] 可能小于 \(0\),这在数组中是不允许的。我们知道,j - A[i] 是由\(i\) 个元素通过加减运算得到得,若运算符号都取反,就能得到 A[i] - j。换句话说,若 \(dp[i][A[i] - j] == true\),则 \(dp[i][j - A[i]] == true\)。所以,我们将 \(dp[i][j - A[i]]\) 改写为 \(dp[i][abs(j - A[i])]\)
  • 2、\(dp[i][j + A[i]]\) 代表 - 这个元素。由题意,我们知道这些元素的最大值,就是所有元素的和 mmax。因此,j + A[i] 不可能大于 mmax。所以,访问 \(dp[i][j + A[i]]\) 的前提是 \(j + A[i] < mmax\)

三、AC代码

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

int quickin(void)
{
	int ret = 0;
	bool flag = false;
	char ch = getchar();
	while (ch < '0' || ch > '9')
	{
		if (ch == '-')    flag = true;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9' && ch != EOF)
	{
		ret = ret * 10 + ch - '0';
		ch = getchar();
	}
	if (flag)    ret = -ret;
	return ret;
}

const int MAX = 1e5 + 5;
int A[105], n, mmax;
bool dp[103][MAX];

int main()
{
	#ifdef LOCAL
	freopen("test.in", "r", stdin);
	#endif
	
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> A[i];
		mmax += A[i];
	}
	
	dp[0][0] = true;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 0; j <= mmax; j++)
		{
			if (j + A[i] <= mmax)
				dp[i][j] |= dp[i - 1][j + A[i]];
			dp[i][j] |= dp[i - 1][abs(j - A[i])];
			dp[i][j] |= dp[i - 1][j];
		}
	}
	ll ans = 0;
	for (int i = 1; i <= mmax; i++)
		if (dp[n][i])
			ans++;
	cout << ans << endl;
	
	return 0;
}

posted @   ltign  阅读(41)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示