原题见HDU 5135
给n(n<13)条边,每条边只能用一次,拼成多个三角形,求三角形面积和的最大值。
分析
1~
212
只有4096,对每个数二进制分解,第i位为1则用
ai
这条边。
预处理出所有的数位和为3的倍数的边。
d[i]
i的二进制数位和
f[i]
用了i的二进制所表示的边后,可以组成的三角形面积的最大值。
如果d[i] = d[j]+3
且i|j <= i
(避免0被1与1组成的情况)
则f[i]=max(f[i], f[i^j])
附代码
#include <bits/stdc++.h>
using namespace std;
#define N 12
double a[N];
int b[1<<N+10], d[1<<N+10], cnt;
double f[1<<N+10];
int dig(int x){
int r = 0;
while(x){
r += x%2;
x >>= 1;
}
return r;
}
void init(){
int all = 1 << N;
cnt = 0;
for(int i = 0;i < all;i++){
d[i] = dig(i);
if(d[i] % 3 == 0)
b[cnt++] = i;
}
}
double gao(int x){
int r = 0;
int g[N];
memset(g, 0, sizeof(g));
while(x){
g[r++] = x%2;
x /= 2;
}
double p = 0;
for(int i = 0;i < r;i++)
if(g[i]) p += a[i];
p /= 2;
double s = p;
for(int i = 0;i < r;i++) if(g[i]){
if(p-a[i] < 0+1e-8) return 0;
s *= p-a[i];
}
return sqrt(s);
}
int main(){
int n;
init();
while(scanf("%d", &n), n){
for(int i = 0;i < n;i++)
scanf("%lf", &a[i]);
int all = 1<<n;
for(int i = 0; i < all;i++)
f[i] = 0;
for(int i = 0;i < cnt && b[i] < all;i++)
if(d[b[i]] == 3){
f[b[i]] = gao(b[i]);
}
double ans = 0;
for(int i = 0;i < cnt && b[i] < all;i++){
for(int j = 0;j <= i;j++){
if(((b[i]|b[j]) <= b[i]) && d[b[i]^b[j]] == 3){
f[b[i]] = max(f[b[i]], f[b[j]]+f[b[i]^b[j]]);
ans = max(ans, f[b[i]]);
}
}
}
printf("%.2f\n", ans);
}
return 0;
}