zoukankan      html  css  js  c++  java
  • 最大 k 乘积问题 ( 经典区间DP )

    题意 : 设 NUM 是一个 n 位十进制整数。如果将 NUM 划分为 k 段,则可得到 k 个整数。这 k 个整数的乘积称为 NUM 的一个 k 乘积。试设计一个算法,对于给定的 NUM 和 k,求出 NUM 的最大 k 乘积

    分析 : 

    定义 dp[i][j] = 前 i 个数字中间插入 j 个乘号时候的最大乘积是多少

    初始化 dp[ i ][ 0 ] = NUM(1, i)  1 <= i <= len(NUM)

    最后的结果则存于 dp[n][k] 

    状态转移方程为 dp[i][j] = max( dp[i][j] ,  dp[m][j-1] * NUM[m+1 ~ i] )   j-1 < m < i

    注 : NUM[a~b] 表示 NUM 的第 a 位到第 b 位组成的数字

    关于状态转移方程先来看一个例子 n = 4、k = 2、NUM = 1231

    首先初始化

    dp[1][0] = 1

    dp[2][0] = 12

    dp[3][0] = 123

    dp[4][0] = 1231

    然后安插 1 个乘号的时候各个长度的最大乘积

    dp[2][1] = dp[1][0] * 2 = 2

    dp[3][1] = max( dp[1][0]*23、dp[2][0]*3 ) = 36

    dp[4][1] = max( dp[1][0]*231、dp[2][0]*31、dp[3][0]*1 ) = 372

    接着是安插 2 个乘号的时候

    dp[3][2] = dp[2][1] * 3 = 6

    dp[4][2] = max( dp[2][1]*31、dp[3][1]*1 ) = 62

    细细去推一下这个例子,可能就会发现更加理解了这个 dp

    可以看出这个 dp 定义的第二维应该是阶段、而第一维是 dp 的状态

    换句话说只有知道在各个长度安插 1 个乘号的结果才能推出各个长度安插 2 个乘号的结果

    C++版

    #include<bits/stdc++.h>
    #define LL long long
    using namespace std;
    const int maxn = 15;
    LL dp[maxn][maxn];
    char num[maxn];
    
    LL GetVal(int st, int en)
    {
        LL ret = 0;
        for(int i=st; i<=en; i++)
            ret = ret * 10 + (num[i] - '0');
        return ret;
    }
    
    int main(void)
    {
        int n, k;
        while(~scanf("%d %d", &n, &k)){
            scanf("%s", (num+1));
            for(int i=1; i<=n; i++)
                dp[i][0] = GetVal(1, i);
    
            for(int j=1; j<=k-1; j++)
                for(int i=j+1; i<=n; i++)
                    for(int m=j; m<i; m++)
                        dp[i][j] = max(dp[i][j], dp[m][j-1]*GetVal(m+1, i));
    
            printf("%lld
    ", dp[n][k-1]);
        }
        return 0;
    }
    View Code

    JAVA大数版

    import java.io.*;
    import java.lang.reflect.Array;
    import java.util.*;
    import java.math.*;
    import java.util.Arrays;
    public class Main {
        static BigInteger[][] dp = new BigInteger[15][15];
        public static void main(String[] args){
            Scanner cin = new Scanner (new BufferedInputStream(System.in));
            
            int n, k;
            String s;
            
            while(cin.hasNext()){
                n = cin.nextInt();
                k = cin.nextInt();
    
                s = cin.next();
                for(int i=1; i<=n; i++){
                    dp[i][0] = BigInteger.valueOf( Integer.parseInt(s.substring(0,i)) );
                    //System.out.println(dp[i][0]);
                }
                
                for(int j=1; j<=k-1; j++)
                    for(int i=j+1; i<=n; i++){
                        dp[i][j] = BigInteger.ZERO;
                        for(int m=j; m<i; m++){
                            if(dp[i][j].compareTo(dp[m][j-1].multiply( BigInteger.valueOf( Integer.parseInt(s.substring(m, i)) ) )) < 0)
                                dp[i][j] = dp[m][j-1].multiply( BigInteger.valueOf( Integer.parseInt(s.substring(m, i)) ) );
                        }
                    }
                
                System.out.println(dp[n][k-1]);
            }
        }
    }
    View Code
  • 相关阅读:
    java api 中的设计模式之组合(composite)
    Java api 中设计模式之适配器模式(Adapter)
    win 7 C盘清理
    centos 与 redhat 以及 mysql 与 Oracle
    tsung生成报表时报错
    对MySQL的死连接Sleep的进程的来源研究[转]
    商派ecstore后台配置微信支付应该注意的问题
    商派crm的内存计算组件配置mysql5.6的问题
    php-curl无法编译
    ecstore目录系统预占字符
  • 原文地址:https://www.cnblogs.com/qwertiLH/p/8082107.html
Copyright © 2011-2022 走看看