链接http://acm.hdu.edu.cn/showproblem.php?pid=1159
基础dp,挑战上的题目。
主要在于体会如何找到状态转移方程,dp的思想我现在理解来看觉得是在于怎么将一个大的问题分解成多个子问题求解,找到子问题的最优解,在比较几个子问题的最优解从而得出当前问题的最优解。然而又可以将每个子问题像这样的方式分下去,找到最优子结构。一直分解问题直到最开始的边界情况,也就是可以直接得出解的情况。
对于最长公共子序列来说,可以定义dp[i][j]为s0~si-1 和 t0~ti-1的最长公共子序列,那么对于每个dp[i+1][j+1]可以由dp[i+1][j]和dp[i][j+1]转移过来,以及如果si+1 == ti+1的时候那么这个还可以从dp[i][j]+1转移过来,这时候要找到最优解,就是比较这三个找出最大的那个。
dp[i+1][j+1] = max(dp[i+1][j],dp[i][j+1],dp[i][j]+1) (si+1 == ti+1时)
dp[i+1][j+1] = max(dp[i+1][j],dp[i][j+1]) (others)
但是思考一下会发现,当 si+1 == ti+1时,最大就是dp[i][j]+1,因为dp[i+1][j]和dp[i][j+1]最好的情况就是等于dp[i][j]+1所以我们可以直接在si+1 == ti+1时 省略另外两个。。
代码
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define M 1009 char s[M],t[M]; int dp[M][M]; int main() { while(scanf("%s %s",s,t)==2) { memset(dp,0,sizeof(dp)); int n = strlen(s); int m = strlen(t); for(int i = 0;i < n;i++) { for(int j = 0;j < m;j++) { if(s[i]==t[j]) dp[i+1][j+1] = dp[i][j]+1; else dp[i+1][j+1] = max(dp[i][j+1],dp[i+1][j]); } } printf("%d\n",dp[n][m]); } return 0; }