经典规划
1.最大连续子序列和
给定一个数字序列
A
1
,
A
2
,
.
.
.
,
A
n
A_1,A_2,...,A_n
A1,A2,...,An,求
i
,
j
(
i
≤
j
≤
n
)
,
i,j(i\le j\le n) ,
i,j(i≤j≤n),使得
A
i
+
.
.
.
+
A
j
A_i+...+A_j
Ai+...+Aj最大,输出这个最大和
步骤1:令状态
d
p
[
i
]
dp[i]
dp[i]表示以
A
[
i
]
A[i]
A[i]作为作为末尾的连续序列最大和,求解
d
p
[
i
]
dp[i]
dp[i]数组
步骤2:考虑两种情况
1
◯
\text{\textcircled 1}
1◯ 该序列只有一个元素,
d
p
[
0
]
=
A
[
0
]
;
dp[0] = A[0];
dp[0]=A[0];
2
◯
\text{\textcircled 2}
2◯该序列有多个元素,
d
p
[
i
]
=
m
a
x
{
A
[
i
]
,
d
p
[
i
−
1
]
+
A
[
i
]
}
dp[i]=max\{ A[i],dp[i-1]+A[i]\}
dp[i]=max{A[i],dp[i−1]+A[i]}
(
状
态
转
移
方
程
)
(状态转移方程)
(状态转移方程)
2.最长不下降子序列(LIS)
在一个数字序列中,找到一个最长的子序列(可以不连续),使得这个子序列是不下降的
步骤1:令状态
d
p
[
i
]
dp[i]
dp[i]表示以
A
[
i
]
A[i]
A[i]作为作为末尾的
L
I
S
LIS
LIS长度
步骤2:对于
A
[
i
]
A[i]
A[i]有两种情况
1
◯
\text{\textcircled 1}
1◯
A
[
i
]
≥
A
[
j
]
(
j
<
i
)
且
d
p
[
j
]
+
1
>
d
p
[
i
]
,
d
p
[
i
]
=
d
p
[
j
]
+
1
;
A[i]\ge A[j]\ (j< i)\ 且\ dp[j]+1>dp[i],\ dp[i] = dp[j]+1;
A[i]≥A[j] (j<i) 且 dp[j]+1>dp[i], dp[i]=dp[j]+1;
2
◯
\text{\textcircled 2}
2◯如果
A
[
i
]
A[i]
A[i]之前的元素都比
A
[
i
]
A[i]
A[i]大,则只能自己形成一条链,且长度为1;
最后得出状态转移方程:
d
p
[
i
]
=
m
a
x
{
1
,
d
p
[
j
]
+
1
}
(
j
=
1
,
2
,
⋯
,
i
−
1
&
&
A
[
j
]
<
A
[
i
]
)
dp[i] = max\{1,dp[j]+1\}\\\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (j=1,2,\dotsb,i-1 \&\& A[j]<A[i])
dp[i]=max{1,dp[j]+1} (j=1,2,⋯,i−1&&A[j]<A[i])
3.最长公共子序列(LCS)
给定两个字符串
A
,
B
A,B
A,B,求一个字符串,使得这个字符串是
A
和
B
A和B
A和B的最长公共部分(子序列可以不连续)
例如 sadstory 和 adminsorry 的最长公共子序列为 adsory
步骤1:令状态
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示字符串
A
A
A的
i
i
i号位和字符串
B
B
B的
j
j
j号位之前的
L
C
S
LCS
LCS长度(下标从1开始)
步骤2: 两种决策
1
◯
\text{\textcircled 1}
1◯ 若
A
[
i
]
=
=
B
[
j
]
A[i]==B[j]
A[i]==B[j],则
d
p
[
i
]
[
j
]
=
d
p
[
i
−
1
]
[
j
−
1
]
+
1
dp[i][j]=dp[i-1][j-1]+1
dp[i][j]=dp[i−1][j−1]+1
2
◯
\text{\textcircled 2}
2◯ 若
A
[
i
]
!
=
B
[
j
]
A[i]!=B[j]
A[i]!=B[j],
L
C
S
LCS
LCS无法延长,则继承
d
p
[
i
−
1
]
[
j
]
,
d
p
[
i
]
[
j
−
1
]
dp[i-1][j],dp[i][j-1]
dp[i−1][j],dp[i][j−1]中的最大值
由此可以得到状态转移方程:
d
p
[
i
]
[
j
]
=
{
d
p
[
i
−
1
]
[
j
−
1
]
+
1
,
A
[
i
]
=
=
B
[
j
]
m
a
x
{
d
p
[
i
−
1
]
[
j
]
,
d
p
[
i
]
[
j
−
1
]
}
,
A
[
i
]
!
=
B
[
j
]
dp[i][j]=\begin{cases} dp[i-1][j-1]+1,\ A[i]==B[j]\\max\{dp[i-1][j],dp[i][j-1] \},\ A[i]!=B[j]\end{cases}
dp[i][j]={dp[i−1][j−1]+1, A[i]==B[j]max{dp[i−1][j],dp[i][j−1]}, A[i]!=B[j]
边界条件:
d
p
[
i
]
[
0
]
=
d
p
[
0
]
[
j
]
=
0
(
0
⩽
i
⩽
n
,
0
⩽
j
⩽
n
)
dp[i][0]=dp[0][j]=0(0\leqslant i\leqslant n,0\leqslant j\leqslant n)
dp[i][0]=dp[0][j]=0(0⩽i⩽n,0⩽j⩽n)
4.最长回文子串
给出一个子串
S
S
S,求出其最长回文子串的长度
步骤1: 令状态
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示
S
[
i
]
和
S
[
j
]
S[i]和S[j]
S[i]和S[j]所表示的子串是否为回文子串,是则为1,不是则为0;
步骤2: 讨论两种情况
1
◯
\text{\textcircled 1}
1◯若
S
[
i
]
=
=
S
[
j
]
S[i]==S[j]
S[i]==S[j],则只要
S
[
i
+
1
]
−
S
[
j
−
1
]
S[i+1]-S[j-1]
S[i+1]−S[j−1]是回文串,则
S
[
i
]
−
S
[
j
]
S[i]-S[j]
S[i]−S[j]就是,否则都不是
2
◯
\text{\textcircled 2}
2◯若
S
[
i
]
!
=
S
[
j
]
S[i]!=S[j]
S[i]!=S[j],那么
S
[
i
]
−
S
[
j
]
S[i]-S[j]
S[i]−S[j]一定不是回文串
由此可得,状态转移方程为:
d
p
[
i
]
[
j
]
=
{
d
p
[
i
+
1
]
[
j
−
1
]
,
S
[
i
]
=
=
S
[
j
]
0
,
S
[
i
]
!
=
S
[
j
]
dp[i][j]=\begin{cases}dp[i+1][j-1],S[i]==S[j]\\ 0,S[i]!=S[j]\end{cases}
dp[i][j]={dp[i+1][j−1],S[i]==S[j]0,S[i]!=S[j]
边界:
d
p
[
i
]
[
i
]
=
1
,
d
p
[
i
]
[
i
+
1
]
=
(
S
[
i
]
=
=
S
[
i
+
1
]
)
?
1
:
0
dp[i][i]=1,dp[i][i+1] =(S[i]==S[i+1])?1:0
dp[i][i]=1,dp[i][i+1]=(S[i]==S[i+1])?1:0
按照枚举子串长度,按照子串长度遍历计算每个状态,如不按照子串长度遍历,状态方程会无法转移
for(int L =3;L<=len;L++){//枚举子串长度
for(int i=0;i+L-1<len;i++){
int j =i+L-1;
}
}