ZOJ 1679 Telescope(区间DP变型题)

题意:

给定一个圆和圆周上面的 N 个点,选择其中的 M 个,按照在圆周上的顺序连成一个 M 边形,使得它的面积最大。

(黑书 147 圆和多边形)

思路:

1. 我一开始尝试的是 dp[i, j] 表示前 i 边形在前 j 个点上的最大面积。想来想去,因为三角形的起点和终点无法固定,则要加强下命题;

2. 对于此类循环类型的动态规划,一般想办法和区间 DP 挂上钩。dp[i, d, j] 表示以 i 点出发,且以 [i, i+d-1] 为区间,找到 j 个点的最大面积;

3. 这样的话,枚举 i,输出 dp[i, N, M] 即可。但是仍然无法保证三角形的第三个点的位置。还需要再次加强命题;

4. dp[i, d, j] 表示以 i 点出发,且以 [i, i+d-1] 为区间,以 i+d-1 点结束。找到 j 个点使面积最大的情况。问题变得明朗了;

5. dp[i, d, j] = max(dp[i, d, j], dp[i, k, j-1] + s[i, i+k-1, i+d-1]); 最终时间复杂度被加强为 O(N * N * M * M);

 

#include <iostream>

#include <algorithm>

#include <cmath>

#include <cstdio>

using namespace std;



const int MAXN = 41;

const double PI = acos(-1.0);



double p[MAXN], s[MAXN][MAXN][MAXN], dp[MAXN][MAXN][MAXN];



class CVector {

public:

    CVector(double _x, double _y) : x(_x), y(_y) {}

    double operator * (const CVector& other) const {

        return x * other.y - y * other.x;

    }

private:

    double x, y;

};



void initdata(int n) {

    for (int i = 0; i < n; i++) {

        for (int j = 0; j < n; j++) {

            for (int k = 0; k < n; k++) {

                CVector v1(cos(p[i]*PI*2), sin(p[i]*PI*2));

                CVector v2(cos(p[j]*PI*2), sin(p[j]*PI*2));

                CVector v3(cos(p[k]*PI*2), sin(p[k]*PI*2));

                s[i][j][k] = fabs((v1*v2 + v2*v3 + v3*v1) / 2);

            }

        }

    }

}



int main() {

    int N, M;

    while (scanf("%d%d", &N, &M) && N && M) {

        for (int i = 0; i < N; i++)

            scanf("%lf", &p[i]);

        initdata(N);

        for (int d = 0; d <= N; d++)

            for (int i = 0; i < N; i++)

                for (int m = 0; m <= M; m++)

                    dp[i][d][m] = 0.0;



        for (int d = 3; d <= N; d++) {

            for (int i = 0; i < N; i++) {

                for (int m = 3; m <= M && m <= d; m++)

                    for (int k = m-1; k <= d-1; k++) 

                        dp[i][d][m] = max(dp[i][d][m], dp[i][k][m-1] + s[i][(i+k-1)%N][(i+d-1)%N]);

            }

        }

        double ans = 0.0;

        for (int i = 0; i < N; i++)

            for (int d = M; d <= N; d++)

                ans = max(ans, dp[i][d][M]);

        printf("%.6lf\n", ans);

    }

    return 0;

}

你可能感兴趣的:(scope)