題目
思路
首先本題是一個判斷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;
}