最高的广告牌

题目

956. 最高的广告牌


你正在安装一个广告牌,并希望它高度最大。这块广告牌将有两个钢制支架,两边各一个。每个钢支架的高度必须相等。

你有一堆可以焊接在一起的钢筋 rods。举个例子,如果钢筋的长度为 123,则可以将它们焊接在一起形成长度为 6 的支架。

返回 广告牌的最大可能安装高度 。如果没法安装广告牌,请返回 0 。

示例 1:

1
2
3
输入:[1,2,3,6]
输出:6
解释:我们有两个不相交的子集 {1,2,3} 和 {6},它们具有相同的和 sum = 6。

示例 2:

1
2
3
输入:[1,2,3,4,5,6]
输出:10
解释:我们有两个不相交的子集 {2,3,5} 和 {4,6},它们具有相同的和 sum = 10。

示例 3:

1
2
3
输入:[1,2]
输出:0
解释:没法安装广告牌,所以返回 0。

提示:

  1. 0 <= rods.length <= 20
  2. 1 <= rods[i] <= 1000
  3. sum(rods[i]) <= 5000

题解

方法一:

思路

折半搜索

对于每个支架有三种选择:选择放左边,选择放右边,不选。

总共有n个支架,于是总共有$3^n$种选择情况。n最大为20显然枚举所有情况会超时。

我们可以先枚举前n/2个数的组合情况,并将其存储到哈希表。

然后再枚举后n/2个数的组合情况,并查哈希表是否有对应合法的情况,取最大值即可。

具体做法是,枚举前n/2的组合,哈希表键存储:选取左边支架值的总和-选取右边支架值的总和,值存储:选取左边支架值的总和。

然后枚举后n/2的组合,我们要使得整体左边支架值的总和等于选取右边支架值的总和才是合法情况,说明后n/2个选取左边支架值的总和-选取右边支架值的总和在哈希表中存在相反数则找到一个合法情况。哈希表值存储前n/2个选取左边支架值的总和+当前后n/2个选取左边支架值的总和便是当前广告牌高度

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class Solution {
public:
int tallestBillboard(vector<int>& rods) {
int BASE = 5001;
vector<int> h(2*BASE+5, -1);
int n = rods.size();
int a = n/2, b = n-a;
// cout << a << " " << b << endl;
int asz = 1;
for (int i=0; i<a; i++) asz *= 3;
int bsz = 1;
for (int i=0; i<b; i++) bsz *= 3;
for (int i=0; i<asz; i++) {
int neg = 0, pos = 0, u = i;
for (int j=0; j<a; j++) {
int s = u%3;
if (s == 0) {
neg += rods[j];
} else if (s == 1) {
pos += rods[j];
}
u /= 3;
}
h[pos-neg+BASE] = max(h[pos-neg+BASE], pos);
}
int ans = 0;
for (int i=0; i<bsz; i++) {
int pos = 0, neg = 0, u = i;
for (int j=0; j<b; j++) {
int s = u%3;
if (s == 0) {
neg += rods[j+a];
} else if (s == 1) {
pos += rods[j+a];
}
u /= 3;
}
if (h[neg-pos+BASE] != -1) {
ans = max(ans, pos+h[neg-pos+BASE]);
}
}
return ans;
}
};