D—Match Stick Game (dp)2019南昌网络赛

本文介绍了一种使用动态规划算法解决火柴棒构造数学表达式问题的方法,旨在通过移动火柴棒使表达式的值最大化,同时保持操作符和数字位数不变。通过预处理最小和最大值矩阵,实现高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:哆啦A梦传送门

题意:给出 0~9 十个数字,每个数字都由一些数量的火柴棒构出,现在给你一个表达式,你可以移动一些火柴棒使得这个表达式的值最大,但是要保证新的表达式的操作符与每个数字的位数要和原来的一模一样,最后输出最大表达式的值。

 

题解:参考博客:神犇

我只是加了点注释,方便自己以后回顾。

 

先预处理:

val[i][j][0] 表示位数为i,火柴棒为j的最小值
val[i][j][1] 表示位数为i,火柴棒为j的最大值

 

接着设 dp[i][j]表示前i个数字剩余j条火柴棒数量的最大值。

 

#include<bits/stdc++.h>

using namespace std;

typedef long long LL;
#define INF 0x3f3f3f3f

///val[i][j][0] 表示位数为i,火柴棒为j的最小值
///val[i][j][1] 表示位数为i,火柴棒为j的最大值
LL val[15][75][2];

///dp[i][j]表示前i个,剩余火柴棒为j的最大值
LL dp[110][710];

int num[10]={6,2,5,5,4,5,6,3,7,6};

void init()
{

    for(int i=0;i<=12;i++)
        for(int j=0;j<=72;j++)
        val[i][j][1]=-1e10,val[i][j][0]=INF;

    val[0][0][0]=val[0][0][1]=0;

    for(int i=1;i<=10;i++)///位数
    {
        ///i*7是因为一位数最多有7条火柴棒
        for(int j=1;j<=i*7;j++) ///可使用的火柴棒数
        {
            for(int k=0;k<=9;k++){ ///变换的数字

                if(j<num[k]) continue;
            val[i][j][0]=min(val[i][j][0],val[i-1][j-num[k]][0]*10+k);
            val[i][j][1]=max(val[i][j][1],val[i-1][j-num[k]][1]*10+k);
            
            }
        }
    }


}

char op[110];

///存储每个操作符op前面的数字的位数
int pre[110],cnt;///cnt表示有多少个数字
int main()
{

    int ncase,n;
    cin>>ncase;
    init();

    while(ncase--)
    {
        cin>>n>>op;
//        cout<<op<<endl;

        int len=strlen(op);

        ///last记录前一个字符的位置
        int last=-1,tot=0;
        cnt=0;
        for(int i=0;i<len;i++)
        {
            if(op[i]=='+'||op[i]=='-'){
                pre[++cnt]=i-last-1;
                last=i;
            }

            if(op[i]=='+') tot+=2;
            else if(op[i]=='-') tot++;
            else tot+=num[op[i]-'0'];
        }
        pre[++cnt]=len-last-1;

//        printf("tot=%d\n",tot);

        for(int i=0;i<=n;i++)
            for(int j=0;j<=n*7;j++)
            dp[i][j]=-1e12;

        int item=min(pre[1]*7,tot);
        for(int i=1;i<=item;i++){
            dp[1][tot-i]=max(dp[1][tot-i],val[pre[1]][i][1]);
//            printf("%lld\n",dp[1][tot-i]);
        }

        ///第几个数字
        for(int i=2;i<=cnt;i++)
        {
            ///枚举火柴棒的数量
            for(int j=0;j<=tot;j++)
            {
                item=min(pre[i]*7+2,j);
                for(int k=2;k<=item;k++)///可使用的火柴棒数
                {

                    ///要么减去最小值,要么加上最大值
            dp[i][j-k]=max(dp[i][j-k],dp[i-1][j]-val[pre[i]][k-1][0]);
            dp[i][j-k]=max(dp[i][j-k],dp[i-1][j]+val[pre[i]][k-2][1]);
                }
            }
        }

        printf("%lld\n",dp[cnt][0]);
    }

    return 0;



}

/*
tot=5
-10000000000
1
7
4
5
*/

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值