算法-动态规划

来源:互联网 发布:全国网络平台监管系统 编辑:程序博客网 时间:2024/06/06 07:45

what  基本思想:

1、分解成若干子问题
2、求解子问题
3、从子问题的解得到原问题的解

    从基本思想上看其与分治很像,他们的区别在于子问题是否独立,子问题之间没有关系是分治,子问题不独立则是动态规划。


how  求解步骤:

1、找出最优解的性质,刻画其结构特征
2、递归地定义最优解的值
3、以自底向上的方式计算出最优值
4、根据最优值信息,构造最优解

where  什么时候适用

存在最优子结构

重叠子问题

动态规划最核心的部分就是运用了递归,不断地求子问题的最优解


典例 0-1背包分析

(1) 0-1背包问题的最优解的结构

     决定那些物品放入背包,那些不放,如果放入了n,则其子问题是从n-1个物品选择放在容量W-w(n)背包,如果没有放入n,则从n-1个物品中选择放在容量为W背包中,这构成子问题


(2)递归定义最优解的值

        c[i,w]=0     i=0,或w=0

        c[i,w]=c[i-1,w]    w[i]>w

        c[i,w]=max{c[i-1,w-wi]+vi,c[i-1,w]}  ,i>0且wi<=w


(3)计算背包问题最优解值

  代码中体现了上述分段函数的情况

int KnapsackDP(int n,int*Weights,float* Values) { int i,w,W; /*为二维数组申请空间*/ int** c=(int **)malloc(sizeof(int *)*(n+1)); for(i=0;i<=n;i++){ c[i]=(int *)malloc(sizeof(int *)*(W+1)); } /*初始化二维数组*/ for(w=0;w<=W;w++){ c[0][w]=0; } for(i=1;i<=n;n++){ c[i][0]=0; for(w=1;w<=W;w++){ /*如果物品重量小于背包的剩余重量*/ if(Weights[i-1]<=w){ /*第i个物品放进去的价值大于不放的价值*/ if(Values[i-1]<=w){ /* 第i个物品放入背包*/ c[i][w]=Values[i-1]+c[i-1][w-Weights[i-1]]; } else{ /* 第i个物品不放入背包*/ c[i][w]=c[i-1][w]; } } else{ c[i][w]=c[i-1][w]; } } } return c;}

  时间复杂度O(nW)


(4)求最优解

void OutputKnapsackDP(int n,int W,int *Weights,float *Values,int **c){int x[n];int i;for(i=n;i>1;i--){if(c[i][W]==c[i-1][W]){ /* 重量为W的最优选择的背包中不包含该物品*/x[i-1]=0;}else{x[i-1]=1;W=W-Weights[i-1];   /* 更新背包目前的最大容量*/}}if(c[1][W]==0){   /*第一个物品不放入背包*/x[0]=0;}else{x[0]=1;    /*第一个物品放入背包*/}for(i=0;i<n;i++){if(x[i]==1){printf("Weight:%d,Value:%f\n",Weights[i],Values[i]);}}}

时间复杂度O(n)


总结:

    构造算法最优解的思想和步骤理解了,代码就很容易看明白了,然后仔细看里面变量的取值,循环的条件,判断条件,整个算法就没有问题, 如果遇到动态规划的题,就照着整个步骤认真思考,这样会好很多。

0 0
原创粉丝点击