动态规划经典例题
动态规划
关键在于填表以及输出过程(个人理解)
算法思想
把原问题分解成若干个简单的子问题,保存已解决的子问题答案,避免重复计算。动态规划常应用于有重叠子问题和最优子结构性质的问题。
子问题最优从而达到全局最优。
算法基本步骤
- 找出最优解的性质
- 递归的定义最优值
- 以自底向上的方式计算最优值
- 根据计算最优值的信息构造最优解
经典案例一 0/1背包问题

import java.util.Scanner;
import static sun.misc.Version.println;
public class Dp{
int n,v;//物品数量和容积
int value[];
int weight[];
int dp[][];//dp[i][j]表示i个物品,容积为j时得到的最大价值
public void Maxvalue(){
for(int i=1;i<=n;i++){
for(int j=0;j<=v;j++){//注意下标还有别的写法
if(j>=weight[i]){
dp[i][j]=Math.max(value[i]+dp[i-1][j-weight[i]], //拿了第i个
dp[i-1][j]);//没拿
}
else{
dp[i][j]=dp[i-1][j];
}}
}
for(int i=0;i<=n;i++){
for(int j=0;j<=v;j++){
System.out.print(dp[i][j] + " ");
}
System.out.println();
}
}
public void BestResult(int n,int v){
boolean isAdd[]=new boolean[n+1];//记录物品是否拿了
for(int i=n;i>=1;i--){ // 倒序
if(dp[i][v]==dp[i-1][v]){
isAdd[i]=false;}
else{
isAdd[i]=true;}
v-=weight[i];
}
for(int i=1;i<=n;i++){//把结果正序输出
System.out.println(i+"是"+isAdd[i]);
}
}
public void Init(){
Scanner sc =new Scanner (System.in);
n=sc.nextInt();
v=sc.nextInt();
weight=new int [n+1];
value=new int [n+1];
dp=new int[n][v];
for(int i=1;i<=n;i++){
weight[i]=sc.nextInt();
}
for(int i=1;i<=n;i++){
value[i]=sc.nextInt();
}
}
public static void main(String[] args){
Dp bag=new Dp();
bag.Init();
bag.Maxvalue();
bag.BestResult(bag.n,bag.v);
}
}
经典例题二 矩阵连乘问题

public class dp_matrix {
int j=6;
int p[];
int s[][];//记录断点k
int dp[][];//最小代价
public dp_matrix() {
p=new int[]{10,15,25,35,20,10,40};
s=new int[j][j];
dp=new int[j][j];
}
public void dp_matrix(){
for(int i=0;i<j;i++){
dp[i][i]=0;}
for(int r=2;r<=j;r++){
for(int i=0;i<=j-r;i++){
int n=i+r-1;
dp[i][n]=dp[i+1][n]+p[i]*p[i+1]*p[n+1];//i<j
s[i][n]=i;//在i+1分的
for(int k=i+1;k<n;k++){
int key=dp[i][k]+dp[k+1][n]+p[i]*p[k+1]*p[n];//注意下标
if(key<dp[i][n]){
dp[i][n]=key;//更新
s[i][n]=k;// 更新
}
}}
}}
public void traceBack(int i ,int j){
if(i==j){
System.out.print(i);}
else{
System.out.print("(");
traceBack(i,s[i][j]);
traceBack(s[i][j]+1,j);
System.out.print(")");
}
}
public static void main(String[] args){
dp_matrix matrix=new dp_matrix();
matrix.dp_matrix();
matrix.traceBack(0,5);
}
}
经典例题三 最长公共子序列

public class Dp_Lcs {
public void Maxlength(){
String []m={"a","b","c","d"};
String []n={"b","c","d"};
int x=m.length;
int y=n.length;
int [][] dp=new int[m.length+1][n.length+1];//dp[i][j]表示xi与yi两个序列最长公共子序列的长度
int[][] s=new int[m.length][n.length];//s[i][j]用来储存m[i]与n[j]之间的关系
for(int i=0;i<=x;i++){//初始化
dp[i][0]=0;
}
for(int i=0;i<=y;i++){
dp[0][i]=0;
}
for(int i=1;i<=x;i++){
for(int j=1;j<=y;j++){
if(m[i-1]==(n[j-1])){ //相等时
dp[i][j]=dp[i-1][j-1]+1;//参照图
s[i-1][j-1]=1;
}
else {dp[i][j]=Math.max(dp[i-1][j], dp[i][j-1]);
if(dp[i][j]==dp[i-1][j]){
s[i-1][j-1]=-1;
}
else s[i-1][j-1]=0;
}
}
}
for(int i=0;i<x;i++){
for(int j=0;j<y;j++){
System.out.print(s[i][j]);}
System.out.println();
}
for(int i=0;i<x+1;i++){
for(int j=0;j<y+1;j++){
System.out.print(dp[i][j]);}
System.out.println();
}
System.out.println("最长为"+" ");
LCS(s,m,x,y);
}
public void LCS(int[][] s, String[] m, int i, int j){//{递归遍历s[i][j]
if(i == 0 || j == 0){ return;}
switch (s[i-1][j-1]) {
case 1:
LCS(s,m,i - 1, j - 1);
System.out.println(m[i-1]+ " ");
break;
case 0:
LCS(s,m,i - 2, j);
break;
default:
LCS(s,m,i, j-2);
break;
}
}
public static void main(String[] args) {
Dp_Lcs a=new Dp_Lcs();
a.Maxlength();
}
}

浙公网安备 33010602011771号