十二届蓝桥杯G.砝码称重[DP]

【问题描述】
你有一架天平和N 个砝码,这N 个砝码重量依次是W1, W2…WN。
请你计算一共可以称出多少种不同的重量?
注意砝码可以放在天平两边。
样例:

input:
3
1 4 6
output:
10


就是一个动态规划,每次状态转移dp[ i ][ j ] 表示加上第i个砝码 j 重量是否可以被称出,也就是当前用了1 到 i 种砝码。
     sum+= a[i];//先算出总和,作为j的右边界

dp结构:

for(i = 1;i <= n;i++)

{

       for(j = 1;j <= sum;j++)

     {

           dp[i][j] = dp[i-1][j];//使用i-1个砝码可以得到的j,使用i个砝码也可以得到

           if(!dp[i][j])

           {

                   if(j < a[i]) //如果j小于本砝码质量

                       dp[i][j] = dp[i-1][a[i]-j];//放在另一边得出差值,如果本侧存在a[i]-j,可以相减得出j

                  if(j == a[i])

                       dp[i][j] = 1;

                  if(j > a[i])//j大于当前砝码质量

                       dp[i][j] = dp[i-1][j-a[i]];//如果本侧j-a[i]存在,那么j就可以由a[i]+(j-a[i])得出

           }

       }

   }

n个砝码是否可以拼出j

for(j = 1;j <= sum;j++) if(dp[n][j]) ans++;

#include <bits/stdc++.h>
using namespace std;
const long long inf = 0x7fffffffffffffff;
bool dp[106][100006];
int a[106];
int main()
{
    int i,j,n,sum = 0;
    scanf("%d",&n);
   for(i = 1;i <= n;i++){
       scanf("%d",&a[i]);
       sum+= a[i];
   }

   for(i = 1;i <= n;i++){
       for(j = 1;j <= sum;j++){
           dp[i][j] = dp[i-1][j];
           if(!dp[i][j]){
               if(j < a[i]) dp[i][j] = dp[i-1][a[i]-j];
                   if(j == a[i]) dp[i][j] = 1;
                       if(j > a[i]) dp[i][j] = dp[i-1][j-a[i]];
           }
       }
   }

   long long ans = 0;
    for(j = 1;j <= sum;j++) if(dp[n][j]) ans++;
    printf("%lld",ans);
    return 0;
}

参考:https://blog.csdn.net/m0_46260869/article/details/115838370?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522161883628816780357293970%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=161883628816780357293970&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_v2~rank_v29-2-115838370.first_rank_v2_pc_rank_v29&utm_term=第十二届蓝桥杯砝码称重&spm=1018.2226.3001.4187

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值