算法篇——贪心算法和动态规划

写在前面:

动态规划和贪心算法这几天真的是让我很费神。今天,就拎出来好好在这说一说。

举例:给你一根长度为n的绳子,请把绳子剪成m段,请问最终每段绳子长度的乘积最大值是多少?例如,当绳子的长度为8时,我们剪成3,3,2三段,最大乘积是18。
接下来,我们分别用这两种方法求解。

动态规划

可以应用动态规划求解的问题的特点:
1.求一个问题的最优解;
(求绳子的乘积最大值。)

2.整体问题的最优解依赖各个子问题的最优解;
(我们把长度为n的绳子剪成若干段后的乘积记为f(n),假设我们第一刀剪在了长度为i的位置(0

3.我们把大问题分解成若干个小问题,这些小问题之间还有相会重叠的更小的子问题;
(假设绳子最初的长度是10,我们剪成了4和6的两段,那么f(4)和f(6)就成了f(10)的子问题。我们将长度为4的绳子均分为长度为2的绳子,即f(2)是f(4)的子问题。长度为6的绳子分并存储起来为2和4,f(2)和f(4)是f(6)的子问题。 我们注意到,f(2)是f(4)和f(6)公共的子问题。)

4.从上往下分析问题,从下往上求解问题。
(为了避免重复求解子问题,我们可以用从下往上的顺序先计算小问题的最优解并存储下来,再以此为基础求解大问题的最优解。)

//代码参考
int solution_1(int length){

if(length<2)
return 0;

if(length==2) return 1;
if(length==3) return 2;
int *products=new int[length+1];
products[0]=0;
products[1]=0;
products[2]=1;
products[3]=2;

int max=0;
for(int i=4;i<=length;++i){
   int j=1;
   for(;j<i/2;++j){
    int product=products[j]*products[i-j];
    if(max<product){
       max=product;

}
}

max=products[length];
delete []products;

return max;

} 
}

//在上述代码中,子问题的最优解存储在数组products中。
//数组中第i个元素表示长度为i的绳子剪成若干段之后的最大乘积。
//我们注意到第一个for循环变量i是顺序递增的,这意味着计算顺序是自下而上的。
//因此在求f(i)之前,对于每一个j(j<0
//为了求解f(i),我们需要求出所有可能的f(j)*f(i-j)并比较得出他们的最大值。这是代码中第二个for循环的功能。

贪心算法

与动态规划不一样,我们应用贪心算法解决问题的时候,每一步都可以做出一个贪心的选择,基于这个选择,我们确定能够得到最优解。

//我们按照如下的策略来剪绳子,得到的各段乘积最大
//:当n≥5时,我们尽可能多的剪长度为3的绳子;
//当剩下的绳子长度为4时,把绳子剪成两段长度为2的绳子。

int solution_2(int length){

if(length<2) return 0;
if(length==2) return 1;
if(length==3) return 2;

int timeof_3=length/3;
if(length-3*timeof_3==1)
timeof_3 -=1 ;
int timeof_2=(length-3*timeof_3)/2;

return (int)(pow(3,timeof_3))*(int)(pow(2,timeof_2));

} 

//接下来我们证明这种思路的正确性。
//首先,当n≥5的时候,2(n-2)>n,3(n-3)>n;也就是说当剩下绳子的长度≥5的时候,
//我们可以剪成2或者3长度的段;另外,3(n-3)>2(n-2),因此我们应该尽可能多
//的剪成长度为3的段。前面证明的前提是n≥5;当n=4的时候,2*2>1*3,
//所以这时候均分两段最为合适。


       大家可以结合这个典型的例题仔细反复琢磨,对于理解上很有帮助。

你可能感兴趣的:(Algorithm)