zoukankan      html  css  js  c++  java
  • 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
    ", ans);
        for (auto x: st)
            printf("%d ", x);
        puts("");
    
        return 0;
    }
    /*
    3
    t 1 t 1 x 1
     */
    
  • 相关阅读:
    字符串和数字的相互转换
    考研_计算机网络
    修改Win+E映射
    BFS总结
    关于—— !important
    css中hack是什么
    轮播图 Swiper4.x 代码模板
    微信小程序---数组操作
    小程序-----button 分享按钮
    微信小程序从子页面退回父页面时的数据传递 wx.navigateBack()
  • 原文地址:https://www.cnblogs.com/YDDDD/p/11509513.html
Copyright © 2011-2022 走看看