可能一开始会想到关于数量的dp,但是发现并不好操作
联想01背包,就可以发现,这题和01背包还是有很多共同特点的,我们为什么不拿长度来dp呢?
三角形的变长也有一些比较有趣的性质,,以前都没留意过
一般对于三角形的题目,都可以从这几个特点去思考
假如变长大小关系是a>=b>=c,那么会有b>=(a+b+c)/2 ,0<c<=(a+b+c)/3且会有c<=b
这使我们枚举变长成为了可能。
然后设dp[i][j]表示b为i,c为j这样的变长是否能同时组合出来,很容易列出方程
if(j >= A[i] && dp[j - A[i]][k]) dp[j][k] = 1;
if(k >= A[i] && dp[j][k - A[i]]) dp[j][k] = 1;
其中i是枚举所有的边。这个方法十分类似01背包,只是背包数从1个变成了2个而已~
然后a就可以通过sum-i-j求得,再验证是否能组成三角形,再更新面积,这题就差不多做完了
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<ctime>
#include<functional>
#include<algorithm>using namespace std;
typedef long long LL;
typedef pair<int, int> PII;const int MX = 1e3 + 5;
const int INF = 0x3f3f3f3f;int A[MX];
int dp[MX][MX];int getS(int a, int b, int c) {if(a >= b + c || b >= a + c || c >= a + b) return -1;double p = (a + b + c) / 2.0;return sqrt(p * (p - a) * (p - b) * (p - c)) * 100;
}int main() {int n;while(~scanf("%d", &n)) {memset(dp, 0, sizeof(dp));int sum = 0, V;for(int i = 1; i <= n; i++) {scanf("%d", &A[i]);sum += A[i];}V = sum / 2;int ans = -1;dp[0][0] = 1;for(int i = 1; i <= n; i++) {for(int j = V; j >= 0; j--) {for(int k = j; k >= 0; k--) {if(j >= A[i] && dp[j - A[i]][k]) dp[j][k] = 1;if(k >= A[i] && dp[j][k - A[i]]) dp[j][k] = 1;if(dp[j][k]) ans = max(ans, getS(sum - j - k, j, k));}}}printf("%d\n", ans);}return 0;
}