传送门
// 题意 : 现在有n根木棍, 要求把这些木棍全部用上, 能组成的最大三角形面积是多少. 不能组成输出-1.
思路: 这个问题就很经典了, 我们首先看数据范围, 最多40根, 每根最长40, 那么周长最长1600, 那么我们就要枚举到1600?显然不是的, 我们可以利用好三角形的边长特点, 可以发现最长的边是周长的一半即800, 所以我们设dp[i][j][k] 代表前i个木棍存在两边长为j, k的方案, 那么转移方程就是:
dp[i][j][k] = dp[i-1][j-a[i]][k] || dp[i-1][j][k-a[i]], 前提j >= a[i] || k >= a[i], 很明显我们可以进行压维, 那么就是需要逆向进行, 然后更新完dp数组后, 最后在扫一遍取第三条边存在的方案中取面积最大的即可….
AC Code
const int maxn = 40+5;
int dp[805][805];
int a[maxn];
bool ok(int a, int b, int c) {
return (a+b) > c && (a+c) > b && (b+c) > a;
}
int cal(int a, int b, int c) {
db p = 1.0*(a+b+c)/2;
return sqrt(p*(p-a)*(p-b)*(p-c))*100;
}
void solve()
{
int n, s = 0;
scanf("%d", &n);
for (int i = 1 ; i <= n ; i ++) {
scanf("%d", a+i);
s += a[i];
}
int tot = s/2; dp[0][0] = 1;
for (int i = 1 ; i <= n ; i ++) {
for (int j = tot ; j >= 0 ; j --) {
for (int k = tot ; k >= 0 ; k --) {
if ((j >= a[i] && dp[j-a[i]][k]) || (k >= a[i] && dp[j][k-a[i]]))
dp[j][k] = 1;
}
}
}
int ans = -1;
for (int i = 0 ; i <= tot ; i ++) {
for (int j = 0 ; j <= tot ; j ++) {
if (dp[i][j] && ok(i, j, s-i-j) && ans < cal(i, j, s-i-j)) {
ans = cal(i, j, s-i-j);
}
}
}
printf("%d\n", ans);
}