蓝桥杯每日真题之砝码称重(01背包)

Posted MangataTS

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了蓝桥杯每日真题之砝码称重(01背包)相关的知识,希望对你有一定的参考价值。

题面来源

2021年蓝桥省赛第一场G题

题面连接:http://acm.mangata.ltd/p/P1482

考点

01背包,动态规划

视频讲解

https://www.bilibili.com/video/BV1bY4y1s7J3/

思路

我们定义 f [ i ] [ j ] f[i][j] f[i][j] 表示的是前 i i i 个物品中是否能称出重量为 j j j 的砝码,由于天平是两边都能添加砝码的,于是我们对于右边的来说如果右边的重量大于左边的,我们记为正,反之我们记为负,于是我们对于每一个砝码可以放在左边(权值为负),也可以放在右边(权值为正),也可以不放,那么我们不难得到状态转移:

f [ i ] [ j ] = f [ i − 1 ] [ j ]   ∣ ∣   f [ i − 1 ] [ j − a [ i ] ]   ∣ ∣   f [ i − 1 ] [ j + a [ i ] ] f[i][j] = f[i-1][j] \\ || \\ f[i-1][j-a[i]] \\ || \\ f[i-1][j + a[i]] f[i][j]=f[i1][j]  f[i1][ja[i]]  f[i1][j+a[i]]

中间是 起来的,因为我们能从这三个状态转移过来,注意的是由于 j − a [ i ] j-a[i] ja[i] 是可能会得到负数的,那么对于负数的情况我们其实得到的重量就是他的绝对值,于是我们给它加上绝对值

f [ i ] [ j ] = f [ i − 1 ] [ j ]   ∣ ∣   f [ i − 1 ] [ a b s ( j − a [ i ] ) ]   ∣ ∣   f [ i − 1 ] [ j + a [ i ] ] f[i][j] = f[i-1][j] \\ || \\ f[i-1][abs(j-a[i])] \\ || \\ f[i-1][j + a[i]] f[i][j]=f[i1][j]  f[i1][abs(ja[i])]  f[i1][j+a[i]]

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mod 1000000007
#define endl "\\n"
#define PII pair<int,int>
#define INF 0x3f3f3f3f

const int N = 1e2+10,M = 1e5+10;

int n,a[N],f[N][M];

int main()

	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin>>n;
	int m = 0;
	for(int i = 1;i <= n; ++i) cin>>a[i],m += a[i];
	f[0][0] = 1;
	for(int i = 1;i <= n; ++i)
		for(int j = m;j >= 0; --j)
			f[i][j] = f[i-1][j] || f[i-1][abs(j-a[i])] ||f[i-1][j + a[i]];
	int ans = 0;
	for(int i = 1;i <= m; ++i)
		if(f[n][i]) ans++;
	cout<<ans<<endl;
	return 0;

以上是关于蓝桥杯每日真题之砝码称重(01背包)的主要内容,如果未能解决你的问题,请参考以下文章

LQ0033 砝码称重DP

计算思维题少儿编程 蓝桥杯青少组计算思维题真题及解析第2套

背包DP——砝码称重(未完结)

P1441 砝码称重

P2347 砝码称重 & P1474 货币系统 Money Systems

LQ0256 5个砝码DFS