总结:
dp问题:
状态 - 集合 | 属性
状态计算 - f[i - 1]的状态和 a[i]的思考
闫氏DP分析法:
1.如何理解集合这一概念:在01背包问题中,集合表示选择了满足集合定义条件的所有情况的汇总集合,如,f[3]表示选择了至少选择了i种水果,那么选择{苹果、香蕉、葡萄}和{苹果}和{西瓜、香蕉}都符合条件。集合则表示我需要求解问题的宝藏库
2.至关重要的状态计算方程:紧扣集合的定义,进行状态计算的转移。就本题:【最长上升子序列】而言,f[i]表示以a[i]为最后一项的单调递增子序列。那么结合我们的目标,找到本组数据种最长的单调递增子序列,就要从这一系列以各个a[k]为尾部的子序列中选出最大的。问题就被分解为了计算出每个以a[i]为最后一项的单调递增子序列。从而得到,f[i] = max(f[i],f[j] + 1)。其中,f[i]就解决了表示集合状态变化的问题,也导出了解决DP问题的核心,在每一次状态转移的时候,以不变的要素为锚点,向前找出最后一个变化的位置,按照这个位置的变化来进行状态转移
import java.util.*;
import java.io.*;
//状态:f[i] 表示以a[i]结尾的单调递增子序列的长度
//
public class Main
{
static final int N = 1010;
static int[] a = new int[N];
static int[] f = new int[N];
public static void main(String args[]) throws IOException
{
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
PrintWriter log = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
int n = Integer.parseInt(in.readLine());
int ans = 0;
String[] T = in.readLine().split(" ");
for(int i = 1;i <= n;i ++) a[i] = Integer.parseInt(T[i - 1]);
for(int i = 1;i <= n;i ++)
{
f[i] = 1;
for(int j = 1;j < i;j ++)
{
if(a[j] < a[i]) f[i] = Math.max(f[i],f[j] + 1);
}
}
for(int i = 1;i <= n;i++) ans = Math.max(ans , f[i]);
log.println(ans);
log.flush();
}
}