题目
思路
首先本题是一个判断DP,那么就考虑指标函数如下定义:
d == 0:不存在, d == 1:可以构成边, d == 2:可以构成三角形。
那么就是状态的定义问题,刚开始我想到的是d(i,j,k),分别表示三角形三边。但这样发现1600^3会MLE,所以不可取。
由于根据边的总和s可以根据两边求出第三边,所以这里三边都表示是没有必要的,这里跟技巧枚举那里有点相似,根据已知量能推出来的未知量就不要再枚举/作为状态了。
技巧枚举可以参考:1,2
代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define _for(i,a,b) for(int i = (a); i<(b); i++)
#define _rep(i,a,b) for(int i = (a); i<=(b); i++)
using namespace std;
const int maxn = 40 + 10;
const int maxm = 1600 + 10;
int n, v[maxn], d[maxm][maxm];
// d == 0:不存在, d == 1:可以构成边, d == 2:可以构成三角形
bool tri(int a, int b, int c) {
return a + b > c && a + c > b && b + c > a;
}
int main() {
scanf("%d", &n);
int s = 0;
_rep(i, 1, n) { scanf("%d", &v[i]); s += v[i]; }
d[0][0] = 1;
_rep(i, 1, n)
for (int j = s; j >= 0; j--)
for (int k = s; k >= 0; k--)
if (d[j][k]) {
int len = s - j - k;
if (j + v[i] <= s) {
if (tri(j + v[i], k, len-v[i])) d[j + v[i]][k] = 2;
else d[j + v[i]][k] = 1;
}
if (k + v[i] <= s) {
if (tri(j, k + v[i], len-v[i])) d[j][k + v[i]] = 2;
else d[j][k + v[i]] = 1;
}
}
double ans = 0.0;
_rep(j, 1, s) _rep(k, 1, s) if (d[j][k] == 2) {
int len = s - j - k;
double p = (len + j + k) / 2.0;
ans = max(ans, sqrt(p*(p - len)*(p - j)*(p - k)));
}
if (ans != 0.0) printf("%.0lf\n", floor(ans * 100));
else printf("-1\n");
return 0;
}