问题 D: Route Calculator(DP)

题目描述

You have a grid with H rows and W columns. H+W is even. We denote the cell at the i-th row from the top and the j-th column from the left by (i,j). In any cell (i,j), an integer between 1 and 9 is written if i+j is even, and either '+' or '*' is written if i+j is odd.

You can get a mathematical expression by moving right or down H+W−2 times from (1,1) to (H,W)and concatenating all the characters written in the cells you passed in order. Your task is to maximize the calculated value of the resulting mathematical expression by choosing an arbitrary path from (1,1) to (H,W). If the maximum value is 1015 or less, print the value. Otherwise, print −1.

 

输入

he input consists of a single test case in the format below.

H W
a1,1 ... a1,W
...
aH,1 ... aH,W
The first line consists of two H integers and W (1≤H,W≤50). It is guaranteed that H+W is even. The following H lines represent the characters on the grid. ai,j represents the character written in the cell (i,j). In any cell (i,j), an integer between 1 and 9 is written if i+j is even, and either '+' or '*' is written if i+1 is odd.

 

输出

Print the answer in one line.

思路:

若本题将运算符号全部改成加号,仔细想一下,就是一个dp的模版题。关键是现在运算符号有加号和乘号。这里我们开数组d[i][j][u][v],表示从点(i,j)到点(u,v)连续乘积的最大值,num[i][j]表示当前位置上的原本值。

那么该dp方程为:设dp[i][j]表示从原点到点(i,j)运算的最大值。则对于当前点(i,j),1.若其左边有加号,则取dp[i - 1][j - 1]和dp[i][j - 2]的较大值。2.若上面有加号,则取dp[i - 1][j - 1]和dp[i - 2][j]的较大值,将之前两种情况取得的较大值再取较大值,与num[i][j]相加更新当前的dp[i][j]。

 此外若之前有点能连乘到(i, j),假设其为(u, v),则用dp[u][v] - num[u][v] + d[u][v][i][j]来跟当前dp[i][j]比较,取较大值
 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define  ll long long
#define inf 1e15
#define mod 55
using namespace std;
char mp[100][100];
ll dp[100][100],d[55][55][55][55],num[100][100];
bool ok(char ch){
    if(ch>='0'&&ch<='9')
        return true;
    else return 0;
}
vector<ll>s[1008611];

int main(){
    ll h,w;
    scanf("%lld%lld",&h,&w);
    for(int i=0;i<h;i++){
        scanf("%s",mp[i]);
    }
    for(int i=0;i<h;i++){
        for(int j=0;j<w;j++){
            if(ok(mp[i][j])){
                dp[i][j]=mp[i][j]-'0';
                d[i][j][i][j]=mp[i][j]-'0';
                num[i][j]=mp[i][j]-'0';
            }
        }
    }
    for(int i=0;i<h;i++){
        for(int j=0;j<w;j++){
            for(int u=i;u<h;u++){
                for(int v=j;v<w;v++){
                    if(ok(mp[i][j]) && ok(mp[u][v]) && (u!=i||v!=j)){
                        ll temp = 1;
                        ll flag = 0;
                        if(u - 1 >= i && mp[u - 1][v] == '*'){
                            if(u-2>=i){
                                temp = max(temp, d[i][j][u - 2][v]);
                            }
                                flag = 1;
                        }
                        if(v-1>=j&&mp[u][v-1]=='*'){
                            if(v-2>=j){
                            temp=max(temp, d[i][j][u][v-2]);
                            }
                            flag =1;
                        }
                        if((v - 1 >= j) && (u - 1 >= i) &&(mp[u - 1][v]=='*'||mp[u][v -1]=='*')){
                            temp = max(temp, d[i][j][u- 1][v-1]);
                            flag = 1;
                        }
                        if(flag){
                            d[i][j][u][v] = dp[u][v]*temp;
                            if(d[i][j][u][v]>inf){
                                printf("-1\n");
                                return 0;
                            }
                            if(temp != 1){
                                s[u*mod+v].push_back(i*mod+j);//记录点(u,v,i,j),以便下面找从(i,j)到(u,v)连乘的值
                            }
                        }
                    }
                    
                }
            }
        }
    }
    for(int i=0;i<h;i++){
        for(ll j=0;j<w;j++){
            ll temp = 0;
            if(!ok(mp[i][j]))
                continue;
            if(i-1>=0&&mp[i-1][j]=='+'){
                if(i-2>=0){
                    temp = max(temp, num[i][j] +dp[i - 2][j]);
                }
            }
            if(j - 1 >= 0 && mp[i][j - 1]=='+'){
                if(j-2>=0){
                    temp = max(temp,num[i][j]+dp[i][j - 2]);
                }
            }
            if(j-1>=0&&i-1>= 0&&(mp[i - 1][j]=='+'||mp[i][j - 1]=='+')){
                temp=max(temp,num[i][j]+dp[i - 1][j - 1]);
            }
            if(s[i*mod+j].size()){
                for(int k=0;k<s[i*mod+ j].size(); k++){
                    ll beg,en;
                    ll v = s[i * mod+ j][k];
                    beg=v/mod;en=v%mod;
                    temp = max(temp, dp[beg][en]-num[beg][en]+d[beg][en][i][j]);
                }
            }
            dp[i][j] = max(temp, num[i][j]);
            if(dp[i][j] > inf){
                printf("-1\n");
                return 0;
            }
        }
    }
    printf("%lld\n",dp[h-1][w-1]);
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值