備忘錄法:
實際上就是遞歸的一種改進,將子問題放入數組中,在遞歸的時候就進行保存,並判斷數組中的值是否被計算過,如果計算過就返回數組的值,否則繼續遞歸併存入數組中。去除了重複的問題
動態規劃法:
動態規劃是將多階段決策問題進行公式化的一種技術,它是運籌學的一個分支,用於求解多階段決策過程的最優化問題。
特點:有相似的子問題,最優子結構。
實際上就是將子問題存入一維數組或者二維數組。。。。。中去,
子問題之間有一定的關係表達式
實例:
斐波那契數列
1.備忘錄法:
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
static int dp[]=new int[105];
static int n;
public static int f(int n ) {
if(n<=1)return n;//遞歸結束條件
if(dp[n]==0)dp[n]=f(n-1)+f(n-2);
return dp[n];
}
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
while(cin.hasNext()) {
n=cin.nextInt();
System.out.println(f(n));
}
}
}
遞歸樹:
2.動態規劃
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
static int n;
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
while(cin.hasNext()) {
n=cin.nextInt();
int dp[]=new int[n+1];
dp[0]=0;dp[1]=1;
for(int i=2;i<=n;i++) {
dp[i]=dp[i-1]+dp[i-2];
}
System.out.println(dp[n]);
}
}
}
路徑計數:
題目大致意思是:人只能每次向下走,或者向右走一格,黃色格子代表障礙物,不可以走。問人一共可以有多少種走法。
遞歸分析:
如果按照一開始的走法,那路徑和等於向下和向右走的路徑之和,同時如何遇到石頭,走的路徑爲0,走到最後一行或一列路徑就之加1
int countPaths(boolean[][] grid, int row, int col){
if (!validSquare(grid, row, col) // 遇到石塊,走0步!
return 0;
if (isAtEnd(grid, row, col)) // 走到end,只需一步!
return 1;
// 向下走的個數+想右走的個數!
return countPaths(grid, row-1, col) + countPaths(grid, row, col+1);
}
————————————————
版權聲明:本文爲CSDN博主「samlee666」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/ILUU121/article/details/101624917
動態規劃:
如果我們從最下面的end開始看,對於end的上,左兩個格子要想走到end,只有一種走法,同理對於最後一行的格子,每次只能向右走,而不能向下走,所以路徑爲1,對於最後一列也可得,每次格子只能向下走。
從後往前填表
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
static int dp[][]=new int[105][105];
static int a[][]=new int[105][105];
static int n;
static int m;
public static int f(int n,int m) {
for(int i=1;i<=m;i++) {
dp[n][i]=1;
}//最後一行
for(int i=1;i<=n;i++) {
dp[i][m]=1;
}//最後一列
for(int i=n-1;i>=1;i--) {
for(int j=m-1;j>=1;j--) {
if(a[i][j]==1) {//表示空地
dp[i][j] = dp[i+1][j] + dp[i][j+1];}
else {
dp[i][j]=0;//表示有障礙,則步數爲0
}
}
}
return dp[1][1];
}
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
while(cin.hasNext()) {
n=cin.nextInt();//行
m=cin.nextInt();//列
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
a[i][j]=cin.nextInt();
}
}//圖的形狀
System.out.println(f(n,m));
}
}
}
輸入的數據:
8//行
8//列
//0代表障礙
1 1 1 1 1 1 1 1
1 1 0 1 1 1 0 1
1 1 1 1 0 1 1 1
0 1 0 1 1 0 1 1
1 1 0 1 1 1 1 1
1 1 1 0 0 1 0 1
1 0 1 1 1 0 1 1
1 1 1 1 1 1 1 1
結果:27
數字三角形
如下圖所示的數字三角形,從三角形的頂部到底部有很多條不同的路徑。對於每條路徑,把路徑上面的數加起來可以得到一個和,和最大的路徑稱爲最佳路徑。編寫一個程序求出最佳路徑上的數字之和。
7
3 8
8 1 2
2 7 4 4
4 5 2 6 5
輸入
多組樣例輸入,每組第一行輸入三角形的層數n,接下來n行輸入三角形。
輸出
輸出最佳路徑上的數字之和。
樣例輸入 Copy
2
1
1 2
3
1
1 2
1 2 3
備忘錄法
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
static int dp[][]=new int [105][105];
static int arr[][]=new int[105][105];
static int n;
public static int f(int i,int j) {
if(dp[i][j]>=0) return dp[i][j]; //引入備忘錄保存子問題的解
if(i==n+1) return 0;
return dp[i][j]=arr[i][j]+Math.max(f(i+1,j),f(i+1,j+1));
}
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
while(cin.hasNext()) {
n=cin.nextInt();
for(int i=1;i<=n;i++) {
for(int j=1;j<=i;j++) {
arr[i][j]=cin.nextInt();
dp[i][j]=-1;
}
}
System.out.println(f(1,1));
}
}
}
動態規劃
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
while(cin.hasNext()) {
int n=cin.nextInt();
int arr[][]=new int[n+1][n+1];
int f[][]=new int[n+1][n+1];
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
arr[i][j]=cin.nextInt();
}
}
for(int i=1;i<=n;i++){
f[n][i]=arr[n][i];
}
for(int i=n-1;i>=1;i--){
for(int j=1;j<=i;j++){
f[i][j]=Math.max(f[i+1][j],f[i+1][j+1])+arr[i][j];
}
}
System.out.println(f[1][1]);
}
}
}
最長公共子序列問題(LCS)
求解兩個序列的最長公共子序列的長度。
輸入
每組輸入包括兩行,每行包括一個字符串。
輸出
兩個序列的最長公共子序列的長度。
樣例輸入 Copy
ACBCDABD
ABDCABA
樣例輸出 Copy
5
備忘錄法
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
static int dp[][]=new int [105][105];
static int arr[][]=new int[105][105];
public static int f(char arr1[],char arr2[],int n,int m) {
if(n==0||m==0) {
return 0;
}else if(arr1[n-1]==arr2[m-1]) {
dp[n][m]=f(arr1,arr2,n-1,m-1)+1;
}else {
dp[n][m]=Math.max(f(arr1,arr2,n-1,m),f(arr1,arr2,n,m-1));}
return dp[n][m];
}
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
while(cin.hasNext()) {
String a=cin.next();
String b=cin.next();
char[] arr1=a.toCharArray();
char[] arr2=b.toCharArray();
System.out.println(f(arr1,arr2,arr1.length,arr2.length));
}
}
}
動態規劃
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
static int dp[][]=new int [105][105];
static int arr[][]=new int[105][105];
public static void f(char arr1[],char arr2[],int n,int m) {
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
if(arr1[i-1]==arr2[j-1]) {
dp[i][j]=dp[i-1][j-1]+1;
}else {
dp[i][j]=Math.max(dp[i-1][j], dp[i][j-1]);
}
}
}
System.out.println(dp[n][m]);
}
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
while(cin.hasNext()) {
String a=cin.next();
String b=cin.next();
char[] arr1=a.toCharArray();
char[] arr2=b.toCharArray();
f(arr1,arr2,arr1.length,arr2.length);
}
}
}