Match Stick Game(dp 搜索)

原题: https://nanti.jisuanke.com/t/38223

题意:

有用火柴拼出的式子,求通过移动火柴拼出的结果的最大值。

解析:

dp[i][j]表示到了第i个数,还剩j根火柴的最大值。+号两根火柴,-号一根。枚举下一个数用的火柴数,对于加号的数,直接找最大值即可。先考虑第一位为9的情况,不行再换。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ll long long
#define DEBU
ll used[10]={6,2,5,5,4,5,6,3,7,6};
ll wei[12]={0,1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000};
char x[109];
const int ff[]={6,2,5,5,4,5,6,3,7,6};
int bit[109],ct;
LL dp[109][709];

ll dfsmax(int now,int res,int digi){
    if(now==1&&(digi*2>res)){
        return -1e18;
    }
    if(now>digi) return 0;
    for(int i=9;i>=0;i--){
        if(res-used[i]>=2*(digi-now)){
            return wei[(digi-now+1)]*i+dfsmax(now+1,res-used[i],digi);
        }
    }
}
ll dfsmin(int now,int res,int digi){
    if(now==1&&(digi*2>res)){
        return 1e18;
    }
    if(now>digi) return 0;
    int dow=(now==1?1:0);
    for(int i=dow;i<=9;i++){
        if(res-used[i]>=2*(digi-now)){
            return wei[(digi-now+1)]*i+dfsmin(now+1,res-used[i],digi);
        }
    }
}

ll fin(bool f,int wei,int ct){
    if(f)
        return dfsmax(1,ct,wei);
    else
        return dfsmin(1,ct,wei);
}

int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int len;scanf("%d",&len);
        scanf("%s",x);
        int sum=0;
        ct=0;
        int num=0;
        for(int i=0;i<len;i++){
            if(x[i]<='9'&&x[i]>='0')sum+=ff[x[i]-'0'],num++;
            else {
                bit[++ct]=num;
                num=0;
                if(x[i]=='-')sum++;
                else sum+=2;
            }
        }
        bit[++ct]=num;
        for(int i=1;i<=ct;i++){
            for(int j=0;j<=sum;j++)
                dp[i][j]=-1e18;
        }

        for(int i=bit[1]*2;i<=bit[1]*7;i++)
            if(sum-i>=0)
                dp[1][sum-i]=max(dp[1][sum-i],fin(1,bit[1],i));
        for(int i=2;i<=ct;i++){
            int use;
            int add;
            for(int j=bit[i]*2;j<=bit[i]*7;j++){
                use=1+j;
                add=-fin(0,bit[i],j);
                for(int k=use;k<=sum;k++){
                    if(dp[i-1][k]<-1e12)continue;
                    dp[i][k-use]=max(dp[i][k-use],dp[i-1][k]+add);
                }
            }
            for(int j=bit[i]*2;j<=bit[i]*7;j++){
                use=2+j;
                add=fin(1,bit[i],j);
                for(int k=use;k<=sum;k++){
                    if(dp[i-1][k]<-1e12)continue;
                    dp[i][k-use]=max(dp[i][k-use],dp[i-1][k]+add);
                }
            }
        }
        cout<<dp[ct][0]<<endl;
#ifdef DEBUG
        for(int i=1;i<=ct;i++){
            for(int j=0;j<=sum;j++){
                if(dp[i][j]>-1e12){
                    printf("dp[%d][%d]=%lld\n",i,j,dp[i][j]);
                }
            }
        }
#endif // DEBUG
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/89422239