1.数字三角最大值路径
package com.smart.domain;
import java.util.Scanner;
/**
* http://blog.csdn.net/baidu_28312631/article/details/47418773
* 递归
* 递归+缓存(从前往后)
* 优化空间的DP(从后往前+一维数组)
* */
/**
* 重叠子问题---计算最大值 可以等价于第一步+后面最优 后面最优=走第二步+后面最优
* 状态---边界状态+一般状态
* 状态转移方程
* */
/**
* 能用动规解决的问题的特点
1.问题具有最优子结构性质。
如果问题的最优解所包含的子问题的解也是最优的,我们就称该问题具有最优子结构性质。
2.无后效性。
当前的若干个状态值一旦确定,则此后过程的演变就只和这若干个状态的值有关,和之前是采取哪种手段或经过哪条路径演变到当前的这若干个状态,没有关系。
* */
public class Test {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int n=scanner.nextInt();
int[][] D=new int[n+1][n+1];
int[] maxarr=new int[n+1];
for (int i = 1; i <=n ; i++) {
for (int j = 1; j <=i ; j++) { //下三角形
D[i][j]=scanner.nextInt();
}
}
for (int j = 1; j <=n ; j++) {
maxarr[j]=D[n][j];//maxarr最开始的时候等于最下面数组的元素值
}
for (int j = n-1; j >=1 ; j--) {
for (int k = 1; k <=j ; k++) {
maxarr[k]=Math.max(maxarr[k],maxarr[k+1])+D[j][k];
}
}
System.out.println(maxarr[1]);
}
}
2.最长公共子序列
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
String s1=scanner.next();
String s2=scanner.next();
int l1=s1.length();
int l2=s2.length();
int l=Math.max(l1,l2);
int[][] maxlen=new int[l+1][l+1]; //maxlen[i][j]表示s1(0,i)和s2(0,j)最长公共子序列长度
//边界状态
for (int i = 0; i <l ; i++) {
maxlen[0][i]=0;
maxlen[i][0]=0;
}
//状态转移过程
for (int i = 1; i <=l1 ; i++) {
for (int j = 1; j <=l2 ; j++) {
if (s1.charAt(i-1)==s2.charAt(j-1)){
maxlen[i][j]=maxlen[i-1][j-1]+1;
}else{
maxlen[i][j]=Math.max(maxlen[i][j-1],maxlen[i-1][j]);
}
}
}
System.out.println(maxlen[l1][l2]);
}
}
3.最长上升子序列
解决方法:
排序+DP
动态
动态+二分搜索
参考资料:http://blog.csdn.net/baidu_28312631/article/details/47426445
解法一:
package com.smart.domain;
/**
* 解题步骤:
*
1. 找子问题
求序列的前n个元素的最长上升子序列的长度”是个子问题,但这样分解子问题,不具有“无后效性”,因为假设F(n) = x,但可能有多个序列满足F(n) = x。
有的序列的最后一个元素比 an+1小,则加上an+1就能形成更长上 升子序列;
有的序列最后一个元素不比an+1小……以后的事情受如何达到状态n的影响,不符合“无后效性” ,
因此我们必须换一种思路来解决此问题。
“求以ak(k=1, 2, 3…N)为终点的最长上升子序列的长度”,一个上升子序列中最右边的那个数,称为该子序列的 “终点”。
虽然这个子问题和原问题形式上并不完全一样,但是只要这N个子问题都解决了,那么这N个子问题的解中, 最大的那个就是整个问题的解。
2.确定状态
子问题只和一个变量---数字的位置相关。
因此序列中数的位置k就是“状态”,而状态 k 对应的“值”,就是以ak做为“终点”的最长上升子序列的长度。
状态一共有N个。
3.找出状态转移方程
maxLen (k)表示以ak做为“终点”的
最长上升子序列的长度那么:
初始状态:maxLen (1) = 1
maxLen (k) = max { maxLen (i):1<=i < k 且 ai < ak且 k≠1 } + 1
若找不到这样的i,则maxLen(k) = 1
maxLen(k)的值,就是在ak左边,“终点”数值小于ak ,且长度最大的那个上升子序列的长度再加1。
因为ak左边任何“终点”小于ak的子序列,加上ak后就能形成一个更长的上升子序列
* */
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int n=scanner.nextInt();
int[] narr=new int[n+1];
int[] max=new int[n+1];
for (int i = 1; i <=n ; i++) {
narr[i]=scanner.nextInt();
max[i]=1;
}
narr[1]=1;
//人人为我
for (int i = 2; i <=n ; i++) {
for (int j = 1; j <i ; j++) {
if (narr[i]>narr[j]){
max[i]=Math.max(max[i],max[j]+1);
}
}
}
System.out.println(max[n]);
}
}
解法二:
package com.smart.domain;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int n=scanner.nextInt();
int[] narr=new int[n+1];
int[] max=new int[n+1];
for (int i = 1; i <=n ; i++) {
narr[i]=scanner.nextInt();
max[i]=1;
}
narr[1]=1;
//我为人人
for (int i = 1; i <=n ; i++) {
for (int j = i+1; j <=n ; j++) {
if (narr[j]>narr[i]){
max[j]=Math.max(max[j],max[i]+1);
}
}
}
System.out.println(max[n]);
}
}
解法三:
package com.smart.domain;
/**
* http://blog.csdn.net/shuangde800/article/details/7474903
* http://www.slyar.com/blog/longest-ordered-subsequence.html
*
* 但是需要注意本身栈的弹出还是使用数组
* 排序+LCS算法 以及 DP算法
* */
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] narr = new int[n+1];
int[] mystack=new int[n+1];
int top=1;//二分查找使用
for (int i = 1; i <= n; i++) {
narr[i] = scanner.nextInt();
}
mystack[1]=Integer.MIN_VALUE;//先放进一个最小的整数
for (int i = 1; i < n; i++) {
if (narr[i]>mystack[top]) {
mystack[++top]=narr[i];
}else{
//二分查找
int low=0,mid=0,high=top;
while(low<high){
mid=low+(high-low)/2;
if (narr[i]>mystack[mid]){
low=mid+1;
}else if (narr[i]<mystack[mid]){
high=mid-1;
}
}
mystack[low]=narr[i];
}
}
System.out.println(top-1);//插入数据的次数就是最大增长子序列长度 因为更换的操作是不会影响最长长度 但是本身需要减一
}
}
4.青蛙跳台阶
/**
* 变态台阶问题
* http://www.cnblogs.com/batys/p/3329955.html
* */
import java.util.Scanner;
public class Test {
public static int FB(int i){
if (i==1){
return 1;
}else if (i==2){
return 2;
}else{
return FB(i-1)+FB(i-2);
}
}
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int n=scanner.nextInt();
int[] narray=new int[n];
for (int i = 0; i <n ; i++) {
narray[i]=scanner.nextInt()-1; //注意这道题目已经处在第一个台阶上面了,因此到第二个台阶只有1种方法。 http://exercise.acmcoder.com/online/online_judge_ques?ques_id=1668&konwledgeId=136
}
for (int i=0;i<n;i++){
System.out.println(FB(narray[i]));
}
}
}
5.苹果分盘子
package dynamic;
import java.util.Scanner;
/**
* m个苹果放入n个盘子
* https://www.nowcoder.com/practice/a2a1d0266629404fba582d416d84b6a0?tpId=61&&tqId=29533&rp=1&ru=/activity/oj&qru=/ta/pku-kaoyan/question-ranking
* https://my.oschina.net/lucusguo/blog/524678
* */
public class Test {
//递归
public static int division(int m,int n){
if (m==0||n==1){ //关键点一:理解m==0出现的情况
return 1;
}else if (m<n){ //关键点二:m不能等于n
return division(m,m);
}else{
return division(m-n,n)+division(m,n-1);
}
}
//DP
public static int dp(int m,int n){
int[][] dparray=new int[m+1][n+1];
for (int i = 0; i <=m ; i++) {
for (int j = 1; j <=n ; j++) {
if (i==0||j==1){
dparray[i][j]=1;
}else{
if (i<j){
dparray[i][j]=dparray[i][i];
}else{
dparray[i][j]=dparray[i-j][j]+dparray[i][j-1];
}
}
}
}
return dparray[m][n];
}
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
while (scanner.hasNext()){
int m=scanner.nextInt();//苹果数量
int n=scanner.nextInt();//盘子数量
System.out.println(division(m,n));
System.out.println(dp(m,n));
}
}
}
6.最长子串之和
package com.smart.domain;
/**
*
* 子问题:
* 其划分方式和最长增加子序列类似,都不是以后续n-1为整体 而是以ak(k=2,3,...)为终点,考虑前面的结果
*
* 状态:
* s[k]代表数组[0,...k]的和
*
* 状态转移方程
* sum[k]=max{a[k]+sum[k],a[k]} 但是注意这个不是最终的结果 这个只是代表了每个位置最大的和 我们只是需要中间最大值
* */
/**
* 如果是子序列?直接大于零的就可以加上
* 如果是k个子序列?转换为寻找最大最小k个数之和
* 如果是k个子串?岂不是更加简单 只需要每次计算k个数之和 max就可以了
* */
//参考链接:http://blog.csdn.net/sgbfblog/article/details/8032464
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] narr = new int[n+1];
int[] sum=new int[n+1];
for (int i = 1; i <= n; i++) {
narr[i] = scanner.nextInt();
}
sum[1]=narr[1];
int max=Integer.MIN_VALUE;
for (int j = 2; j <=n ; j++) {
sum[j]=Math.max(sum[j-1]+narr[j],narr[j]);
if (sum[j]>max){
max=sum[j];
}
}
System.out.println(max);
}
}