试题 历届真题 砝码称重(保姆分析)

试题 历届真题 砝码称重【第十二届】【省赛】【A组】

.
试题 G: 砝码称重
【问题描述】
你有一架天平和 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。
分析:开始我还想采用递归,我的天写写画画,放弃告终,看了其他文章,发现使用dp,对于一个小白来说,看到dp就紧张,最后看了一下发现我还是能够理解的(废话,纯属记录生活)
通过状态逐渐向下,首先要知道,定义了两个数组:dp[i][a[j]],a[j],a[j]表示的是重量,dp中的i表示第几个状态,如果有此重量我们给dp[i][a[j]]赋值为1;如列子,第一个状态就是1,
第二个状态是加入4,然后加减:1+4,4-1,那么第二个状态就有:1,4 ,5 ,3
那么第三个状态加入6:就有1-6,1+6,4-6,4+6,5+6,5-6,3-6,3+6还要继承上一状态
因为我们是赋值1嘛重复时也不怕:所以第三状态为:1到10
废话不多说,
附上代码:

#include<iostream>
#include<algorithm>
using namespace std;
int dp[110][10006] = {0};
int a[110];
int main()
{
	//采用dp算法
	int n,sum=0,ans=0;
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
		sum += a[i];
	}
	
	//开始dp状态逐渐转移
	//第一个状态a[1]是肯定存在的
		dp[1][a[1]] = 1;//i表示第几个状态,a[j]表示重量
	for (int i = 2; i <= n; i++)//其他状态,继承状态
	{
		int x = a[i];//把值赋给x便于编写
		for (int j = 1; j <= sum; j++)//把上一个状态赋给当前状态
			//主要是看存在1的dp
		{
			dp[i][j] = dp[i - 1][j];
		}
		dp[i][x] = 1;//传入当前数的状态
		for (int j = 1; j <= sum; j++)//开始加减传入数
		{
			if (dp[i-1][j] == 1)//如果执行时有数子的才进行加减
			{
				dp[i][j + x] = 1;//加法
				dp[i][abs(j - x)] = 1;//减法
			}

		}
	
	
	}
	for (int j = 1; j <= sum; j++)
	{
		if (dp[n][j] == 1)
		{
			ans++;
		}
	}
	cout << ans << endl;
}

运行代码:
在这里插入图片描述

  • 23
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yjg_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值