来学习dp了,关于dp优化空间
首先要想这道题目暴力搜索肯定没办法过,想dp,想dp的四个步骤,确定子问题,定义状态,转移方程,判断无重复计算
确定子问题感觉和定义状态是一起的也就是判断dp数组该怎么定义维数并且能够覆盖所有子问题
最开始想到的维数肯定是最大的,毕竟要包括所有的子问题,之后再优化
定义dp[i][j][p][q],比对到第i个数,已经有第j个数成功被子串覆盖,当前进行匹配第p个串,q值为0或者1表示第i个数是否选择(选择肯定要和第j个数相等)
子问题就是a比对到第i个数,b中已经有j个字符匹配,匹配到第p个子串,第i个数选择是否的可行方案数
这么就可以覆盖所有的子问题了
状态转移方程是最简单的了,一开始想出来是这样的
dp[i][j][p][0] = dp[i - 1][j][p][0] + dp[i - 1][j][p - 1][1];
if(a[i] == b[j]) dp[i][j][p][1] = dp[i - 1][j - 1][p][1] + dp[i - 1][j - 1][p][0];
由因为是四维,所以我通过遍历每一个dp状态比对是否正确的debug效率特别慢,哭死我了/(ㄒoㄒ)/~~
最后找到问题了,问题是我这个状态只能体现| aab |子串, 不能体现|a| + |ab|子串,也就是我默认了子串之间一定有至少一个字符不选择导致错误转移
最后正确的转移方程
dp[i][j][p][0] = dp[i - 1][j][p][0] + dp[i - 1][j][p - 1][1];
if(a[i] == b[j])
dp[i][j][p][1] = dp[i - 1][j - 1][p][1] + dp[i - 1][j - 1][p][0] + dp[i - 1][j - 1][p - 1][1];
然后放心大胆的交发现mel了,空间复杂度是n * m * k,8e8超了
然后考虑优化,优化空间思路现在知道两个一个是滚动数组和直接优化掉某一维(就是背包优化)
滚动也就是利用更新发现的特性,发现更新只需要前一列元素,所以只用保留前一列就行了
其实通过这个叙述就感觉能用滚动数组的题目就可以直接将那一维优化掉了
直接贴代码
#include
#define int long long
using namespace std;
const int N = 1e3 + 10, M = 2e2 + 10, mod = 1000000007;
string a, b;
//int dp[2][M][M][2];//i,j, p, q一维表示截至为a第i个字符,二维表示截至为匹配到b第j个字符,三维表示当前处于匹配了p个子窜,四维表示第i个数选择或者不选
//滚动数组,将可优化维转化为只有1和0的维
//signed main() {
// int n, m, k;
// cin >> n >> m >> k;
// cin >> a >> b;
//
// //dp[0][0][1][0] = 1;
// dp[0][0][1][0] = dp[1][0][1][0] = 1;
// for (int i = 1; i <= n; i++) {
// for (int j = 1; j <= m; j++) {
// for (int p = 1; p <= k + 1; p++) {
// dp[i & 1][j][p][0] = (dp[!(i & 1)][j][p][0] + dp[!(i & 1)][j][p - 1][1]) % mod;
// if (a[i - 1] == b[j - 1]) {
// dp[i & 1][j][p][1] = (dp[!(i & 1)][j - 1][p][1] + dp[!(i & 1)][j - 1][p][0] + dp[!(i & 1)][j - 1][p - 1][1]) % mod;
// }
// else {
// dp[i & 1][j][p][1] = 0;
// }
// }
// }
// }
//
// cout << (dp[n & 1][m][k][1] + dp[n & 1][m][k + 1][0]) % mod;
// return 0;
//}
//在滚动数组的基础上直接将第一维优化掉,虽然没必要
int dp[M][M][2];
signed main() {
int n, m, k;
cin >> n >> m >> k;
cin >> a >> b;
dp[0][1][0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = m; j >= 1; j--) {
for (int p = k + 1; p >= 1; p--) {
dp[j][p][0] = (dp[j][p][0] + dp[j][p - 1][1]) % mod;
if (a[i - 1] == b[j - 1]) {
dp[j][p][1] = (dp[j - 1][p][1] + dp[j - 1][p][0] + dp[j - 1][p - 1][1]) % mod;
}
else dp[j][p][1] = 0;
}
}
}
cout << (dp[m][k][1] + dp[m][k + 1][0]) % mod;
return 0;
}