`
qingdaoguy
  • 浏览: 23572 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

一道经典的动态规划问题题解

阅读更多

一道经典的动态规划问题题解

 

有一个由数字12...9组成的数字串(长度不超过200),问如何将M(M<=20)个加号("+")插入到这个数字串中,使所形成的算术表达式的值最小。请编一个程序解决这个问题。

注意:
加号不能加在数字串的最前面或最末尾,也不应有两个或两个以上的加号相邻。
M
保证小于数字串的长度。

例如:数字串79846,若需要加入两个加号,则最佳方案为79+8+46,算术表达式的值133

[输入格式]

从键盘读入输入文件名。数字串在输入文件的第一行行首(数字串中间无空格且不折行),M的值在输入文件的第二行行首。

[输出格式]

在屏幕上输出所求得的最小和的精确值。

[输入输出举例]

EXAM4.SAM
82363983742
3

输 入 输 出

EXAM4.SAM 2170

 

 

   易知,若用蛮力法进行求解,够呛了。明显,这是道经典的动态规划问题:

规划方程:

getResult[start,end]=min{getResult[start,index]+Num[index,end]} (start<index<=end-1)

边界值: getResult[0,end]= NUM[1,end] ;

其中:getResult[start,end]表示数字串第startend位最小和

      Num[index,end]表示数字串从第indexend位所组成的数

注意到上式中,index取值范围极广。然而我们对该题细细分析时,发现当最小和时,组成该最小和的任意两个加法因子的长度不大于1

故每个加法因子长度只的可能为m/(n+1)m/(n+1)+1(这里m表示数字串的长度,n表示加法号个数),当(n+1|m时,每个数字串长度便确定了,可直接求出。有了此约束条件,该算法的复杂度便下降了。其java实现程序如下:

 

import javax.swing.*;

import java.math.*;

public class Adders {

   

    private String numExp;      //定义数字串

    private int addNum;          //定义加法号个数

    private  int lengthPerNum;  //定义每个加法因子的最小长度

   

    public Adders(){

       //输入数字串和加法号个数,并求得LengthPerNum

       numExp = JOptionPane.showInputDialog(null,"Please input the expression of numbers:");

       addNum = Integer.parseInt(JOptionPane.showInputDialog(null,"the number of adding :"));

       lengthPerNum = numExp.length() / (addNum + 1);

    }

    //将数字串strNum转为数字

    private BigInteger num(String strNum){

       if(strNum.equals("")) return new BigInteger("9999999999");

       return new BigInteger(strNum);

      

    }

    //动态求得结果

    public BigInteger getResultByDp(int index,int num){

 

       if(num == 0)

           return num(numExp.substring(0, index));

       else{

           BigInteger result1;

           BigInteger result2;

           if(index<=lengthPerNum+1 )

              return new BigInteger("999999999");

           result1 = getResultByDp(index - lengthPerNum,num - 1).add(num(numExp.substring(index - lengthPerNum, index))) ;

           result2 = getResultByDp(index - lengthPerNum - 1,num - 1).add(num(numExp.substring(index - lengthPerNum - 1, index))) ;

           if(result1.compareTo(result2)>= 0)

              return result2;

           else

              return result1;

             

       }

    }

    //直接求得结果

    public BigInteger getResultByDiret(){

       BigInteger result = new BigInteger("0") ;

       for(int i=0;i <= addNum;i++)

           result = result.add(num(numExp.substring(i*lengthPerNum,(i+1)*lengthPerNum)));

       return result;

    }

   

    public static  void main(String args[]){

       Adders a = new Adders();

       if(a.numExp.length() == (a.addNum+1)*a.lengthPerNum)

           System.out.println("Result:"+a.getResultByDiret());

       else

           System.out.println("Result:"+a.getResultByDp(a.numExp.length(), a.addNum));

          

    }

}

 

说明:1)这里仅仅实现了求最小和功能,并未严格遵循输入输出规则。

为了防止溢出,使用了高精度数BigInteger

      2)当然,由于长度为m/(n+1)m/(n+1)+1的加法因子个数是确定的,也可以据此用枚举法实现,这里不再赘述。

      3)水平有限,欢迎大牛提出宝贵意见。

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics