最开始接触动态规划,是因为在做题的时候,遇到了一道题,刚开始我用递归很快就做出来了,但不管我怎样跑,都会时间超限。题是这样的:
拿金币
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
有一个N x N的方格,每一个格子都有一些金币,只要站在格子里就能拿到里面的金币。你站在最左上角的格子里,每次可以从一个格子走到它右边或下边的格子里。请问如何走才能拿到最多的金币。
输入格式
第一行输入一个正整数n。
以下n行描述该方格。金币数保证是不超过1000的正整数。输出格式
最多能拿金币数量。
样例输入
3
1 3 3
2 2 2
3 1 2样例输出
11
数据规模和约定
n<=1000
最开始我的代码是这样的:
import java.util.*;
public class Main {
static int sum=0;
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int arr[][]=new int[n][n];
for(int i=0;i<n;i++) {
for(int j=0;j<n;j++) {
arr[i][j]=sc.nextInt();
}
}
jinbi(n,0,0,arr,0);
System.out.println(sum);
}
static void jinbi(int n,int x,int y,int[][] arr,int sumi) {
sumi+=arr[x][y];
if(x<n-1) {
jinbi(n,x+1,y,arr,sumi);
}
if(y<n-1)jinbi(n,x,y+1,arr,sumi);
if(x==n-1&&y==n-1&&sumi>sum) {
sum=sumi;
}
}
}
我这个代码运用了传统递归二叉树的思想,在运算过程中会出现很多重复运算,运算效率不高,时间序是N^x级别的,故多次不能通过。
所以我去网络上查了这道题的解法,发现解这道题需要用的动态规划的思想:
动态规划(Dynamic Programming,DP)是运筹学的一个分支,是求解决策过程最优化的过程。20世纪50年代初,美国数学家贝尔曼(R.Bellman)等人在研究多阶段决策过程的优化问题时,提出了著名的最优化原理,从而创立了动态规划。动态规划的应用极其广泛,包括工程技术、经济、工业生产、军事以及自动化控制等领域,并在背包问题、生产经营问题、资金管理问题、资源分配问题、最短路径问题和复杂系统可靠性问题等中取得了显著的效果
在这道题中:
1、子问题为:sum(n-1)=sum(n-2)+(n-1)
2、状态转移方程为:arr[y][x]=arr[y][x]+Math.max(arr[y-1][x],arr[y][x-1])
所以我写了如下代码:
import java.util.*; public class Main { public static void main(String[] args) { Scanner sc=new Scanner(System.in); int n=sc.nextInt(); long [][] arr=new long[n][n]; for(int i=0;i<arr.length;i++) { for(int j=0;j<arr[0].length;j++) { arr[i][j]=sc.nextInt(); } } System.out.println(najinbi(arr,n)); } static long najinbi(long[][] arr,int n) { for(int y=0;y<arr.length;y++) { for(int x=0;x<arr[0].length;x++) { if(x>0&&y==0) { arr[y][x]=arr[y][x]+arr[y][x-1]; }else if(x==0&&y>0) { arr[y][x]=arr[y][x]+arr[y-1][x]; }else if(y>0) {arr[y][x]=arr[y][x]+Math.max(arr[y-1][x],arr[y][x-1]);} } } return arr[n-1][n-1]; } }
但是这个代码还是超时间限了,其实是犯了一个很小的错误,因为我以为题目中的数据会很大,其实数据规模只有0——1000,但是我用了long,这导致内存超限。后来我把long改成了int,这样程序就全部通过了。
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int [][] arr=new int[n][n];
for(int i=0;i<arr.length;i++) {
for(int j=0;j<arr[0].length;j++) {
arr[i][j]=sc.nextInt();
}
}
System.out.println(najinbi(arr,n));
}
static int najinbi(int [][] arr,int n) {
for(int y=0;y<arr.length;y++) {
for(int x=0;x<arr[0].length;x++) {
if(x>0&&y==0) {
arr[y][x]=arr[y][x]+arr[y][x-1];
}else if(x==0&&y>0) {
arr[y][x]=arr[y][x]+arr[y-1][x];
}else if(y>0) {arr[y][x]=arr[y][x]+Math.max(arr[y-1][x],arr[y][x-1]);}
}
}
return arr[n-1][n-1];
}
}