SPOJ:364 Pocket Money

要你求表达式可以得到的最大值和最小值。

 

一看题意容易联想到UVA 10700这个题。但这个题因为可以出现0使题目复杂了很多,因此用动规来做。

 

已经有人解释的很全面了,引用一下。

 

maxx[i][j]=max{maxx[i][k] operator(+,*) maxx[k+1][j} },表示i到j段的最大值是i到k段和k+1到j段构成的。所以三个for循环枚举区间长度,区间取点,以及分割点k的位置。因为区间长度由小到大,因为这样大区间都是由小区间组成的,这样保证求解大区间时,每个小区间的值已经求解出来了。

 

最后是我写的代码。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int dx[105][105]={0},dn[105][105]={0};
char op[105]={0};
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(dn,-1,sizeof(dn));
        memset(dx,0,sizeof(dx));
        memset(op,0,sizeof(op));
        int n=1,a=0;
        while(scanf("%d%c",&a,&op[n]))
        {
            dx[n][n]=dn[n][n]=a;
            if(op[n]=='\n') break;
            n++;
        }
        for(int k=1;k<n;++k)
         for(int i=1;i+k<=n;++i)
          for(int j=i;j<i+k;++j)
         {
             int mx=0,mn=0;
             if(op[j]=='+')
             {
                 mx=dx[i][j]+dx[j+1][i+k];
                 mn=dn[i][j]+dn[j+1][i+k];
             }
             else
             {
                 mx=dx[i][j]*dx[j+1][i+k];
                 mn=dn[i][j]*dn[j+1][i+k];
             }
             dx[i][i+k]=max(dx[i][i+k],mx);
             if(dn[i][i+k]==-1) dn[i][i+k]=mn;
             dn[i][i+k]=min(dn[i][i+k],mn);
         }
         printf("%d %d\n",dx[1][n],dn[1][n]);
    }
    return 0;
}


 

你可能感兴趣的:(动态规划)