经典问题五.【乘号两边有正负 区间dp】Polygon poj 1179

本文介绍了一种使用区间动态规划解决特定符号运算问题的方法。针对输入的符号串和数值,通过枚举移除边的方式,结合区间DP算法,求解在不同运算符作用下能够达到的最大值。代码实现中详细展示了如何进行状态转移,并记录最优解。

题目描述:
这里写图片描述
思路:
因为n并不大,所以很容易想到枚举一下第一步去掉的边。
然后展开应为符号和点交杂的一条线,如果符号只有‘+’,那么用区间dp求其最优解应该很简单啦,同样小区间推大区间,dp[i][j] = dp[i][k-1]+dp[k][j].现在考虑‘’,不能向‘+’一样简单的相乘就可以,因为如果两边是负数,那么两边最小才能使值最大,那么我们在过程最小值和最大值都需要记忆化,在‘’时,列举四种:(minn*minn , maxn*minn , maxn*maxn , minn*maxn)取最优即可。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 110;

int minn[N][N],maxn[N][N];
int record[N];
char ver[N];
int a[N];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i = 1; i <= n; i++)
    {
        getchar();
        scanf("%c %d",&ver[i],&a[i]);
        ver[i+n] = ver[i];
        a[i+n] = a[i];
    }
    int ans = -INF;
    for(int v = 1; v <= n; v++)
    {
        int x = v, y = v+n-1;
        memset(minn,0,sizeof(minn));
        memset(maxn,0,sizeof(maxn));
        for(int i = x; i <= y; i++)
            minn[i][i] = maxn[i][i] = a[i];
        for(int len = 1; len < n; len++)
        {
            for(int i = x; i+len <= y; i++)
            {
                int l = i, r = i+len;
                maxn[l][r] = -INF;
                minn[l][r] = INF;
                for(int k = l+1; k <= r; k++)
                {
                    if(ver[k] == 't')
                    {
                        maxn[l][r] = max(maxn[l][r],maxn[l][k-1]+maxn[k][r]);
                        minn[l][r] = min(minn[l][r],minn[l][k-1]+minn[k][r]);
                    }
                    else
                    {
                        maxn[l][r] = max(maxn[l][r],maxn[l][k-1]*maxn[k][r]);
                        minn[l][r] = min(minn[l][r],maxn[l][k-1]*maxn[k][r]);
                        maxn[l][r] = max(maxn[l][r],maxn[l][k-1]*minn[k][r]);
                        minn[l][r] = min(minn[l][r],maxn[l][k-1]*minn[k][r]);
                        maxn[l][r] = max(maxn[l][r],minn[l][k-1]*minn[k][r]);
                        minn[l][r] = min(minn[l][r],minn[l][k-1]*minn[k][r]);
                        maxn[l][r] = max(maxn[l][r],minn[l][k-1]*maxn[k][r]);
                        minn[l][r] = min(minn[l][r],minn[l][k-1]*maxn[k][r]);
                    }
                }
            }
        }
        //printf("%d\n",maxn[x][y]);
        record[v] = maxn[x][y];
        if(maxn[x][y] > ans)
            ans = maxn[x][y];
    }
    printf("%d\n",ans);
    int flag = 0;
    for(int v = 1; v <= n; v++)
    {
        if(record[v] == ans)
        {
            if(flag == 0)
                printf("%d",v);
            else
                printf(" %d",v);
            flag = 1;
        }
    }
    puts("");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值