题目描述
奶牛建筑师Hei想建造围有漂亮白色栅栏的三角形牧场。她拥有N(3≤N≤40)块木板,每块的长度Li(1≤Li≤40)都是整数,她想用所有的木板围成一个三角形使得牧场面
积最大。请帮助Hei小姐构造这样的牧场,并计算出这个最大牧场的面积。
输入格式
第1行:一个整数N。
第2…N+1行:每行包含一个整数,即是木板长度。
输出格式
仅一个整数:最大牧场面积乘以100然后舍尾的结果。如果无法构建,输出-1。
样例输入
5
1
1
3
3
4
样例输出
692
思路
看到这道题目,我的第一感觉是用贪心做:使三边更加接近。这样很容易找到反例。
不妨令 =所有木板的长度总和,易知:如果枚举三角形的两边 , ,那么第三边: 。又因为 ,我们便可以想到暴力枚举 , 。
但是万一给定的木板凑不齐 怎么办?这里像不像DP可行性问题的板子?
所以定义bool类型数组 标记给定三角形的i,j两边能不能被给定的木板凑齐
对于每个 ,如果 ,即给定木板可以凑出 , , ,那么给定木板便一定可以凑出 , , ,即 为
我们则可以得出核心代码
if(j >= a[i]) dp[j][k] |= dp[j - a[i]][k];
if(k >= a[i]) dp[j][k] |= dp[j][k - a[i]];
当然,我们还需:
1.判别这三边是否能组成三角形。
2.使用求三角形面积的海伦公式…
这些都是很容易想到的。
代码
#include <cstdio>
#include <algorithm>
#include <climits>
#include <cmath>
#include <cstring>
#define LL long long
using namespace std;
const int MAXN = 45, MAXX = 40 * 40 + 5;
int a[MAXN], dp[MAXX][MAXX], sum;
double t;
bool bol(int x, int y, int z) {
if((x + y) <= z) return 1;
if((x + z) <= y) return 1;
if((y + z) <= x) return 1;
return 0;
}
double hl(int x, int y, int z) {
double ans = sqrt(t * (t - x) * (t - y) * (t - z));
return ans;
}
int main() {
int n, l;
double maxx = -1;
scanf("%d", &n);
for(int i = 1; i <= n; i ++) {
scanf("%d", &a[i]);
sum += a[i];
}
t = sum / 2.0;
dp[0][0] = 1;
for(int i = 1; i <= n; i ++) {
for(int j = sum / 2; j >= 0; j --) {
for(int k = j; k >= 0; k --) {
if(j >= a[i]) dp[j][k] |= dp[j - a[i]][k];
if(k >= a[i]) dp[j][k] |= dp[j][k - a[i]];
}
}
}
for(int i = sum / 2; i > 0; i --) {
for(int j = i; j > 0; j --) {
l = sum - i - j;
if(l < 0) continue;
if(bol(i, j, l) || (!dp[i][j])) continue;
maxx = max(maxx, hl(i, j, l));
}
}
if(maxx == -1) {
printf("-1");
return 0;
}
printf("%d", int(floor(maxx * 100)));
return 0;
}