蓝桥杯刷题——砝码称重(动态规划)

437 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情

这是21年蓝桥杯省赛中的一道题目,所用方法为动态规划,有一定难度。

题目

image.png

image.png

思路

我们从动态规划的角度来分析,首先我们创建一个二维数组dp[i][j],还有一个一维数组shu[]存放砝码,前面的指数i是指取前i个砝码时,我们所能达到的重量。接下来的做法就有些像是01背包了。每次砝码都只能取一次,取或者不取。但是我们取得话会有两种情况,一种是取了放在左边天平上,一种是取了放在右边天平上。假设物品是在右边,而现在我们将砝码放在左边时,我们要怎么判断是否能够称出重量j呢?我们只需这样判断,dp[i-1][abs(j-shu[i])]是否等于1,用当前所需重量的减去当前要加在左边的砝码的绝对值判断是否为1,如果为1,那么j的重量是一定能够称出来的。砝码放在右边时,我们只需判断dp[i-1][j+shu[i]]是否为1,如果为1,那么j的重量也能够称出来。最后我们将能够称出的重量放入set数组中去重,返回set数组的大小,即可得出能够称出的重量的个数。

代码

#include <bits/stdc++.h>
using namespace std;
int n;
int shu[101];
int dp[101][100001];
set<int>s;
int sum=0;
int main()
{
  cin>>n;
  for(int i=1;i<=n;i++){
    cin>>shu[i];
    sum+=shu[i];
  }
  for(int i=1;i<=n;i++){
      for(int j=1;j<=sum;j++){
          dp[i][j]=dp[i-1][j];
        if(!dp[i][j]){
            if(shu[i]==j){
                dp[i][j]=1;
                s.insert(j);
                continue;
            }
            if(dp[i-1][abs(j-shu[i])]){
                dp[i][j]=1;
                s.insert(j);
                continue;
            }
            if(dp[i-1][j+shu[i]])
            {
                dp[i][j]=1;
                s.insert(j);
                continue;
            }
        }else{
            s.insert(j);
        }
    }
  }
  cout<<s.size();
  return 0;
}