试题 历届真题 砝码称重【第十二届】【省赛】【B组】-CSDN博客

48 阅读2分钟
资源限制

时间限制:1.0s 内存限制:256.0MB

 

本题是我做不出的一道题,也是网上搜了题解才明白的,该题的解决办法是 dp

我们分三步走

首先定义一个dp数组根据题意我们定义一个二维数组dp[i][j]涵义为前i个砝码可以称出质量j

其次,我们需要找到数组元素之间的关系表达式,我们这样想,如果前i个砝码可以称出质量j

,那么会与dp[ i-1 ][ j ]或者其他元素有什么关系呢??? (这里有些难)

我们假设在能够使用前 i 个砝码称出质量 j 的情况下,那么必然在放下那最后第 i 个砝码的时候,我们会面临以下三种选择

  1. 放在天平左边
  2. 放在天平右边
  3. 不放

在这三种选择下,为了得到质量 j ,我们必然会得到与之相对应的结果

在上面这样的角度思考,我们便能更好地理解

dp[i][j] = dp[i - 1][abs(j - w[i])] + dp[i - 1][j + w[i]] +dp[i - 1][j]

第三步是初始化dp[0][0] = 1;//前0件可以称出重量为0

下面请看代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int dp[102][100005]={0};//定义dp[i][j]涵义为前i个砝码可以称出质量j 
int w[102];
int n;
int sum = 0;
int main()
{
    scanf("%d",&n);
    for (int i = 1; i <= n; i++) {
        scanf("%d",&w[i]);
        sum += w[i];
    }
    dp[0][0] = 1;//前0件可以称出重量为0
    for (int i = 1; i <= n; i++) {   //有n*sum个状态
        for (int j = 0; j <= sum; j++) {//这里j不能从1开始 必须从0 第一件物品不可能称出0 但是前i件可能称出0
            dp[i][j] = dp[i - 1][abs(j - w[i])] + dp[i - 1][j + w[i]] +dp[i - 1][j];
        }		//这里表达式的意思是 能否用前i个砝码称出质量j,取决于我们要放的砝码w[i]放在左边或者右边或者不放 
    }			//的时候能否称出“对应 ”的质量 
    int ans = 0;
    for (int i = 1; i <= sum; i++) {
        if (dp[n][i] != 0) {//能使用前n个砝码称出质量i 
            ans++;
        }
    }
    printf("%d",ans);
    return 0;
}