算法练习题35---蓝桥杯2021省赛“砝码称重”

文章目录


前言

蓝桥杯2021年省赛,编程题(C++)

这道题主要考察了基础的动态规划思想

一、题目描述

你有一架天平和 N 个砝码,这 N 个砝码重量依次是 W1, W2,⋅⋅⋅, WN。

请你计算一共可以称出多少种不同的重量? 注意砝码可以放在天平两边。

输入格式

输入的第一行包含一个整数 N。

第二行包含 N 个整数:W1,W2,W3,⋅⋅⋅,WN。

输出格式

输出一个整数代表答案。

样例输入

3
1 4 6

样例输出

10

样例说明

能称出的 10 种重量是:1、2、3、4、5、6、7、9、10、11。

1=1;

2 = 6 − 4 (天平一边放 6,另一边放 4);

3=4−1;

4=4;

5=6−1;

6=6;

7=1+6;

9=4+6−1;

10=4+6;

11=1+4+6。

评测用例规模与约定

对于 50%的评测用例,1≤N≤15。

对于所有评测用例,1≤N≤100,N个砝码总重不超过 100000。

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 256M

二、思路

我们对于拿过来的每一种砝码,有两种选择,一种是放,另一种是不放。放的话,其实又有两种选择,一种是放到左边,一种是放到右边,但是注意,放到左边和右边的情况是不一样的。试想,现在天平上左边有1kg , 5kg两个重量的砝码,而天平的右边现在没有砝码,那么我取来一个重7kg的砝码,先选择放到左边,现在重量是1+5+7=13,而假如我放到右边呢,其实最终可以称出来的重量是abs(1+5-7)即1,因此这也引出了解决本题的dp思路。

我们建立dp[i][j]的过程及含义如下:

dp[i][j]表示在当前 i 种砝码下,对于重量 j 来说,是否能够拼凑出来,即dp的值只有0和1两种,1表示能够拼凑出来,0表示不能够拼凑出来。那么对于第 i 个砝码来说,重量为w[i],那么对于某一重量 j ,如果dp[i-1][j]==1,即在前面的砝码已经被遍历的情况下,可以拼凑出 j 这个重量,那么我们有:

dp[i][j]=dp[i-1][j] //这种情况是当前这个砝码选择不放

dp[i][j+w[i]]=1; //这种情况是当前这个砝码放到左边,比如(左:15,右5;实际上可以等于做10,右0)

dp[i][abs(j-w[i])]; //这种情况是当前这个砝码放到右边

思路大致是这样的,下面来看具体代码

三、完整代码

#include<bits/stdc++.h>
using namespace std;
int dp[105][100005];
int w[150];
int main()
{
	int n;
	cin>>n;
	int sum=0;
	for(int i=0;i<n;i++)
	{
		cin>>w[i];
		sum+=w[i];
	}
	sort(w,w+n);  //将砝码从小到大排列
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<=sum;j++)
		{
			dp[i][j]=0;
		}
	}
	dp[0][w[0]]=1;  //第一个砝码先赋初值
	for(int i=1;i<n;i++)  //遍历砝码的次序
	{
		dp[i][w[i]]=1;   //当前重量一定可以称出,即只放这一个砝码
		for(int j=1;j<=sum;j++)  //对于每一种重量,分别判断
		{
			if(dp[i-1][j]==1)  //之前能凑出来这种重量
			{
				dp[i][j]=1;
				dp[i][abs(j-w[i])]=1;
				dp[i][j+w[i]]=1;
			}
		}
	}
	int ans=0;
	for(int i=1;i<=sum;i++)
	{
		if(dp[n-1][i]==1)
		{
			ans++;
		}
	}
	cout<<ans<<endl;
	return 0;
}
上一篇:剑指Offer系列—— 35.复杂链表的复制


下一篇:文件流