poj 1948 Triangular Pastures 二维01背包模板

缘起

研究二维费用01背包~ poj 1948 Triangular Pastures

分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
给N条边,把这些边组成一个三角形,问面积最大是多少?必须把所有边都用上。

【输入】
2行, 第一行是N,第二行N个正整数Li(可能重复)表示边的长度
3 <= N <= 40
1 <= Li <= 40

【输出】
如果不能构成三角形, 输出-1,否则输出面积*100之后的截断整数.

【样例输入】
5
1
1
3
3
4

【样例输出】
692

【限制】
1s

想法是

1
2
3
4
5
6
dp[i][j][k] 是前i条边能否组成j、k长度的边. 则
dp[i][j][k] = dp[i-1][j][k] || dp[i-1][j-li][k] || dp[i-1][j][k-li]
滚动数组优化空间复杂度为
dp[j][k] = dp[j][k] || dp[j-li][k] || dp[j][k-li]
初始化值是dp[0][0] = true, 其余全部是false
最后计算答案的时候, 就只需遍历dp[j][k]即可. 然后使用海伦公式计算面积更新答案.

不难写下如下ac代码(本题转换为01背包还是比较巧妙的~ 转化点就是考虑前i条边能组成什么样的两条边~)

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
//#include "stdafx.h"
#include <stdio.h>
#include <math.h>
#include <algorithm>
using namespace std;
//#define LOCAL

const int maxn = 50;
int n, a[maxn],s;
bool dp[2000][2000];

void zo(int c) // 二维费用01背包
{
for (int j = s; ~j; j--)
{
for (int k = s-j; ~k; k--) // 要灵活啊
{
if (j>=c)
{
dp[j][k] = dp[j][k] || dp[j-c][k];
}
if (k>=c)
{
dp[j][k] = dp[j][k] || dp[j][k-c];
}
}
}
}

bool ck(int a,int b, int c) // a、b、c能否组成三角形
{
return a+b>c && b+c>a && c+a>b;
}

double hellen(int a, int b, int c) // 海伦公式计算三角形面积
{
int s = a+b+c;
return sqrt(s/2.0*(s/2.0-a)*(s/2.0-b)*(s/2.0-c));
}

int main() {
#ifdef LOCAL
freopen("d:\\data.in", "r", stdin);
// freopen("d:\\my.out", "w", stdout);
#endif
scanf("%d", &n);
for (int i = 1;i<=n;i++)
{
scanf("%d", a+i);
s+=a[i];
}
dp[0][0] = true;
for (int i = 1;i<=n;i++)
{
zo(a[i]);
}
double ans = -1;
for (int j = 0;j<=s;j++)
{
for (int k = 0; k<=s-j; k++)
{
if (dp[j][k] && ck(j,k,s-j-k)) // 如果可以组成三角形
{
ans = max(ans, hellen(j,k,s-j-k));
}
}
}
if (ans<0)
{
puts("-1");
}
else
{
printf("%d\n", (int)(ans*100));
}
return 0;
}

ac情况

Status Accepted
Time 422ms
Memory 1980kB
Length 1143
Lang C++
Submitted 2019-10-25 15:07:45
Shared
RemoteRunId 20988838