0w1

UVA 1543 Telescope ( DP )

UVa Online Judge
題目要求圓內選擇 m個點時最大的 m多邊形面積。由於點是給逆時針排序的,所以省掉了做一次凸包的麻煩。以 dp[ i ][ j ][ k ]為 [ i, j ] 中選了 k個點( 包含 i 和 j )時的最大面積動態規劃下去就行了。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 40 + 2;
const double PI = acos( -1.0 );

int n, m;
double p[MAXN];

double dis(int a, int b){
    double d = p[ b ] - p[ a ];
    if( d > 0.5 ) d = 1.0 - d;
    return 2 * sin( d * PI );
}

double area(int a, int b, int c){
    double x = dis( a, b );
    double y = dis( b, c );
    double z = dis( a, c );
    double s = ( x + y + z ) / 2.0;
    return sqrt( s * ( s - x ) * ( s - y ) * ( s - z ) );
}

// dp[i][j][k]: maximum area after chosen k points between [ i, j ]
double dp[MAXN][MAXN][MAXN];
void solve(){
    memset( dp, 0, sizeof(dp) );
    for(int i = 3; i <= m; ++i)
        for(int a = 0; a < n; ++a)
            for(int b = a + 1; b < n; ++b)
                for(int c = b + 1; c < n; ++c)
                    dp[a][c][i] = max<double>( dp[a][c][i], dp[a][b][i - 1] + area( a, b, c ) );
    double ans = 0.0;
    for(int i = 0; i < n; ++i)
        for(int j = i + 1; j < n; ++j)
            ans = max<double>( ans, dp[i][j][m] );
    printf("%.6lf\n", ans);
}

int main(){
    while( scanf("%d%d", &n, &m) == 2 && n + m ){
        for(int i = 0; i < n; ++i)
            scanf("%lf", &p[i]);
        solve();
    }
    return 0;
}