UVa 1543 - Telescope

链接

传送门

题意

给出圆周上的\(n(1 \leq n \leq 40)\)个点,取\(m(1 \leq m \leq n)\)个点围成多边形,输出最大的面积。

思路

\(dp[i][j][k]\)代表取的第一个点为\(i\),最后一个点为\(j\),总共取了\(k\)个点的最大面积。则有\(dp[i][j][k] = max(dp[i][x][k - 1] + S_{ijx});\)

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <cmath>
using namespace std;

typedef long long LL;
const int maxn = 42;
const double PI = acos(-1);
double a[maxn];
double l[maxn][maxn];
double s[maxn][maxn][maxn];
double dp[maxn][maxn][maxn];

inline double dis(int i, int j) {
double x = fabs(a[i] - a[j]);
if (x > 0.5) {
x = 1 - x;
}
return 2 * sin(x * PI);
}

inline double S(int i, int j, int k) {
double a = l[i][j], b = l[j][k], c = l[i][k];
double p = (a + b + c) / 2;
return sqrt(p * (p - a) * (p - b) * (p - c));
}

int main() {
int n, m;
while (~scanf("%d%d", &n, &m) && (n || m)) {
for (int i = 1; i <= n; ++i) {
scanf("%lf", &a[i]);
for (int j = 1; j < i; ++j) {
l[j][i] = dis(i, j);
}
}
for (int i = 1; i <= n; ++i) {
for (int j = i + 1; j <= n; ++j) {
for (int k = j + 1; k <= n; ++k) {
s[i][j][k] = S(i, j, k);
}
}
}
memset(dp, 0, sizeof dp);
for (int k = 3; k <= m; ++k) {
for (int i = 1; i <= n; ++i) {
for (int x = i + k - 2; x <= n; ++x) {
for (int j = x + 1; j <= n; ++j) {
dp[i][j][k] = max(dp[i][j][k], dp[i][x][k - 1] + s[i][x][j]);
}
}
}
}
double ans = 0;
for (int i = 1; i <= n; ++i) {
for (int j = i + 1; j <= n; ++j) {
ans = max(ans, dp[i][j][m]);
}
}
printf("%.6f\n", ans);
}
return 0;
}