题目描述
题解
刚开始有一种错误的贪心策略:将边从大往小加,每次加到最小的里面去,以保证尽量平均。然而我还是too naive,随便反栗:9 7 7 5 5 3 3 1 1 1。
结果想了一下发现就是一个无脑背包。
f(i,j)表示用两拨木棍能不能拼出i和j的长度。显然剩下的就是sum-i-j了嘛。求f(i,j)用一个二维01背包就能解决。转移方程:f(i,j)|=f(i,j-l[k])|f(i-l[k],j);
最后枚举一下两个长度然后用海伦公式算一下就行了。时间复杂度
O(n5)
。
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define N 45
int n,m,sum,l[N];
double p,area,ans;
bool f[N*N][N*N];
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;++i) scanf("%d",&l[i]),sum+=l[i];
m=sum;
f[0][0]=true;
for (int i=1;i<=n;++i)
for (int j=m;j>=0;--j)
for (int k=m;k>=0;--k)
{
if (j-l[i]>=0) f[j][k]|=f[j-l[i]][k];
if (k-l[i]>=0) f[j][k]|=f[j][k-l[i]];
}
double p=(double)sum/2;
for (int i=m;i>=0;--i)
for (int j=m;j>=0;--j)
if (f[i][j])
{
double a=(double)i,b=(double)j,c=(double)sum-(double)i-(double)j;
if (a+b<=c||a+c<=b||b+c<=a) continue;
area=sqrt(p*(p-a)*(p-b)*(p-c));
ans=max(ans,area);
}
if (ans==0) puts("-1");
else
{
ans*=100;
ans=floor(ans);
printf("%0.0lf\n",ans);
}
}
总结
①01背包不能刚开始把所有的先加进去,那样不能保证只用一次。