背包问题-二进制优化

Smiling & Weeping

                  ----不讨好所有冷漠 不辜负所有热爱

 

# [NOIP1996 提高组] 砝码称重

 

## 题目描述

 

设有 1g2g3g5g10g20g 的砝码各若干枚(其总重1000),可以表示成多少种重量?

 

## 输入格式

 

输入方式:a1,a2,a3,a4,a5,a6

 

(表示 1g 砝码有 a1 个,2g 砝码有 a2 个,…,20g 砝码有 a6 个)

 

## 输出格式

 

输出方式:`Total=N`

 

N 表示用这些砝码能称出的不同重量的个数,但不包括一个砝码也不用的情况)

 

## 样例 #1

 

### 样例输入 #1

 

```
1 1 0 0 0 0
```

 

### 样例输出 #1

 

```
Total=3
```

 

## 提示

 

**【题目来源】**

 

NOIP 1996 提高组第四题

复制代码
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 int a[7] = {0,1,2,3,5,10,20} , num[10];
 5 ll dp[10010] , new_value[10010] , n , ans;
 6 int main()
 7 {
 8     for(int i = 1; i <= 6; i++)
 9         scanf("%d",&num[i]) , n += num[i]*a[i];
10     dp[0] = 1;
11     int n_new = 0;
12     for(int i = 1; i <= 6; i++)
13     {
14         for(int j = 1; j <= num[i]; j <<= 1)
15         {
16             num[i] -= j;
17             new_value[++n_new] = j * a[i];
18         }
19         if(num[i])
20         {
21             new_value[++n_new] = num[i] * a[i];
22         }
23     }
24     for(int i = 1; i <= n_new; i++)
25         for(int j = n; j >= 1; j--)
26             if(j >= new_value[i])
27                 dp[j] += dp[j - new_value[i]];
28     for(int i = 1; i <= n; i++)
29         if(dp[i])
30             ans++;
31     cout << "Total=" << ans << endl;
32     return 0;
33 }
复制代码

其实我们可以想到,我们DP的自我滚动从n到1,是为了保证不会像dp[j+new_value[i]] += dp[j]的重复计算

我们从n到1会保证了每个只得到正确的计算次序!!!

加强理解

详见P2347 [NOIP1996 提高组] 砝码称重 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

 

本文作者:Smiling-Weeping

本文链接:https://www.cnblogs.com/smiling-weeping-zhr/p/17519830.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   smiling&weeping  阅读(12)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起