1.数塔DP:
dp[i][j]的含义是第i行第j列的数到最底层的最长路径
状态转移方程:
dp[i][j] = max(d[i+1][j],d[i+1][j+1]) + f[i][j]
边界:
dp[n][] = f[n][]
2.最大连续子序列和:
dp[i]的含义是以A[i]结尾的连续序列最大的和;
状态转移方程:
dp[i] = max(a[i] , a[i] + d[i-1])
边界:
dp[0] = a[0];
3.最长上升子序列LIS:
d[i]的含义是以A[i]结尾的最长上升子序列的长度;
状态转移方程:
dp[i] = max(1 , d[j] + 1)
其中j = 1,2,3,4....,i-1 && A[i] > Aj
边界:
dp[1] = 1;
观察状态转移方程,i与前面的i-1次状态军有关,我们可以让i从小到大遍历,这样就可以覆盖到所有的情况;
代码:
int d[N] , A[N];
for(int i = 1; i <= n; i++)
{
d[i] = 1; //每次开始前把以A[i]结尾的最长子序列长度设置为只有A[i]本身
for(int j = 1; j < i; j++)
{
if(A[i] > A[j] && d[j] + 1 > d[i])
{
d[i] = d[j] + 1;
}
}
}
int ans = 0;
for(int i=1; i<=n; i++)
{
if(d[i] > ans) ans = d[i];
}
4.最长公共子序列LCS:
d[i][j]的含义:表示A串前i位,与B串前j位,的最大公共子序列
状态转移方程:
if(A[i] == B[j])
d[i][j] = d[i-1][j-1] + 1;
else
d[i][j] = max(d[i-1][j] , d[i][j-1]);
边界:
d[i][0] = 0 , d[0][j] = 0;
代码从边界出发遍历,就可以得到整个数组;
5.最长回文子串:
d[i][j]的含义:表示串的第i位到第j位的字串是否是回文串;
状态转移方程:
if(S[i] == S[j])
{
if(dp[i+1][j-1] == 1)
{
dp[i][j] == 1;
}
}
else
{
dp[i][j] = 0;
}
边界:
d[i][i] = 1 , d[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; //字串右端点
if(S[i] == S[j] && d[i+1][j-1] == 1)
{
dp[i][j] = 1;
ans = L'
}
}
}