Acwing-283-多边形(区间DP)

链接:

https://www.acwing.com/problem/content/285/

题意:

“多边形游戏”是一款单人益智游戏。

游戏开始时,给定玩家一个具有N个顶点N条边(编号1-N)的多边形,如图1所示,其中N = 4。

每个顶点上写有一个整数,每个边上标有一个运算符+(加号)或运算符*(乘号)。

1179_1.jpg

第一步,玩家选择一条边,将它删除。

接下来在进行N-1步,在每一步中,玩家选择一条边,把这条边以及该边连接的两个顶点用一个新的顶点代替,新顶点上的整数值等于删去的两个顶点上的数按照删去的边上标有的符号进行计算得到的结果。

下面是用图1给出的四边形进行游戏的全过程。

1179_2.jpg

最终,游戏仅剩一个顶点,顶点上的数值就是玩家的得分,上图玩家得分为0。

请计算对于给定的N边形,玩家最高能获得多少分,以及第一步有哪些策略可以使玩家获得最高得分。

思路:

先处理环, 将环变成链式再扩大两倍,就可以处理环了,从l-(l+n-1)的范围就是将l前面的边在第一步断开的情况.
考虑步数, 对两个堆进行dp, 操作受到符号限制.

代码:

#include <bits/stdc++.h>
using namespace std;
const int INF = 1e9;
const int NINF = -1e9;

int a[110], op[110];
int Dp[110][110][2];
int n;
char ope;

int main()
{
    scanf("%d", &n);
    getchar();
    for (int i = 1;i <= n;i++)
    {
        scanf("%c%d", &ope, &a[i]);
        getchar();
//        cout << ope << endl;
        if (ope == 't')
            op[i] = 1;
        else
            op[i] = 0;
    }
    for (int i = n+1;i <= 2*n;i++)
    {
        a[i] = a[i-n];
        op[i] = op[i-n];
    }
    for (int i = 1;i <= 2*n;i++)
    {
        for (int j = 1;j <= 2*n;j++)
        {
            Dp[i][j][0] = NINF, Dp[i][j][1] = INF;
            if (i == j)
                Dp[i][j][0] = Dp[i][j][1] = a[i];
        }
    }
//    for (int i = 1;i <= 2*n;i++)
//        cout << op[i] << ' ' << a[i] << ' ' ;
//    cout << endl;
    for (int len = 2;len <= n;len++)
    {
        for (int l = 1;l <= 2*n-len+1;l++)
        {
            int r = l+len-1;
            for (int k = l;k < r;k++)
            {
                if (op[k+1] == 1)
                {
                    Dp[l][r][0] = max(Dp[l][r][0], Dp[l][k][0]+Dp[k+1][r][0]);
                    Dp[l][r][1] = min(Dp[l][r][1], Dp[l][k][1]+Dp[k+1][r][1]);
                }
                else
                {
                    Dp[l][r][0] = max(Dp[l][r][0], Dp[l][k][0]*Dp[k+1][r][0]);
//                    Dp[l][r][0] = max(Dp[l][r][0], Dp[l][k][0]+Dp[k+1][r][0]);
                    Dp[l][r][0] = max(Dp[l][r][0], Dp[l][k][1]*Dp[k+1][r][1]);
                    Dp[l][r][0] = max(Dp[l][r][0], Dp[l][k][1]*Dp[k+1][r][0]);
                    Dp[l][r][0] = max(Dp[l][r][0], Dp[l][k][0]*Dp[k+1][r][1]);

                    Dp[l][r][1] = min(Dp[l][r][1], Dp[l][k][1]*Dp[k+1][r][1]);
//                    Dp[l][r][1] = min(Dp[l][r][1], Dp[l][k][1]+Dp[k+1][r][1]);
                    Dp[l][r][1] = min(Dp[l][r][1], Dp[l][k][0]*Dp[k+1][r][0]);
                    Dp[l][r][1] = min(Dp[l][r][1], Dp[l][k][1]*Dp[k+1][r][0]);
                    Dp[l][r][1] = min(Dp[l][r][1], Dp[l][k][0]*Dp[k+1][r][1]);
                }
            }
        }
    }
    int ans = NINF;
    for (int l = 1;l <= n+1;l++)
    {
        int r = l+n-1;
//        cout << Dp[l][r][0] << endl;
        ans = max(ans, Dp[l][r][0]);
    }
    set<int> st;
    for (int l = 1;l <= n;l++)
    {
        int r = l+n-1;
        if (Dp[l][r][0] == ans)
            st.insert(l);
    }
    printf("%d\n", ans);
    for (auto x: st)
        printf("%d ", x);
    puts("");

    return 0;
}
/*
3
t 1 t 1 x 1
 */
posted @ 2019-09-11 23:30  YDDDD  阅读(187)  评论(0编辑  收藏  举报