☆lightoj1013 Love Calculator 两种转移方程详解(LCS+方案数DP)
来源:互联网 发布:摇杆下载软件 编辑:程序博客网 时间:2024/05/08 13:51
Yes, you are developing a 'Love calculator'. The software would be quite complex such that nobody could crack the exact behavior of the software.
So, given two names your software will generate the percentage of their 'love' according to their names. The software requires the following things:
1. The length of the shortest string that contains the names as subsequence.
2. Total number of unique shortest strings which contain the names as subsequence.
Now your task is to find these parts.
Input
Input starts with an integer T (≤ 125), denoting the number of test cases.
Each of the test cases consists of two lines each containing a name. The names will contain no more than 30 capital letters.
Output
For each of the test cases, you need to print one line of output. The output for each test case starts with the test case number, followed by the shortest length of the string and the number of unique strings that satisfies the given conditions.
You can assume that the number of unique strings will always be less than 263. Look at the sample output for the exact format.
Sample Input
Output for Sample Input
3
USA
USSR
LAILI
MAJNU
SHAHJAHAN
MOMTAJ
Case 1: 5 3
Case 2: 9 40
Case 3: 13 15
(2) dp[i][j][k] 表示前i个字符恰好包含s0前j个字符,包含s1前k个字符的方案数;
若 s0[j] =s1[k] dp[i][j][k]=dp[i-1][j-1][k-1];
若 s0[j]!=s1[k] dp[i][j][k]=dp[i-1][j-1][k]+dp[i-1][j][k-1];
cnt[i][0][i] = cnt[i][i][0] = 1;因为当前序列如果都是一个序列的组成的,肯定就是只有1种情况也就是=1
#include <iostream>#include <cstdio>#include <cstring>using namespace std;const int maxn = 50;typedef long long ll;ll dp[maxn][maxn], cnt[maxn*2][maxn][maxn];char s1[maxn], s2[maxn];int main(){ int t, ca = 1; cin >> t; while(t--) { cin >> s1 >> s2;// cout << s1 << endl << s2 << endl; memset(dp, 0, sizeof(dp)); memset(cnt, 0, sizeof(cnt)); int len1 = strlen(s1); int len2 = strlen(s2); for(int i = 1; i <= len1; i++) for(int j = 1; j <= len2; j++) { if(s1[i-1] == s2[j-1]) dp[i][j] = dp[i-1][j-1] + 1; else dp[i][j] = max(dp[i-1][j], dp[i][j-1]); } int l = len1 + len2 - dp[len1][len2]; cnt[0][0][0] = 1; for(int i = 1; i <= l; i++) { cnt[i][0][i] = cnt[i][i][0] = 1; for(int j = 1; j <= min(len1,i); j++) for(int k = 1; k <= min(len2,i); k++) { if(s1[j-1] == s2[k-1]) cnt[i][j][k] = cnt[i-1][j-1][k-1]; else cnt[i][j][k] = cnt[i-1][j-1][k] + cnt[i-1][j][k-1]; } } printf("Case %d: %d %lld\n", ca++, l, cnt[l][len1][len2]); } return 0;}法二:
解析:设两个字符串 A、B,长度为n、m。
最短长度显然就是 n+m-lcs(A,B)。
令f[i][j]为A的前i个字符和B的前j个字符组成的最短长度,dp[i][j]为个数
若A[i]=A[j],f[i][j] = f[i-1][j-1]+1,dp[i][j] = dp[i-1][j-1]
反之,分为f[i-1][j]和f[i][j-1]两个情况。
思路:dp[i][j]为构造a[1]−a[i] 和 b[1]−b[j]的最短长度,ans[i][j]表示在该状态下的方案数。
(1)a[i]==b[j]
dp[i][j]=dp[i−1][j−1]+1
ans[i][j]=ans[i−1][j−1]
(2)a[i]!=b[j]
1、dp[i−1][j]<dp[i][j−1]
dp[i][j]=dp[i−1][j]+1ans[i][j]=ans[i−1][j]
2、dp[i−1][j]>dp[i][j−1]
dp[i][j]=dp[i][j−1]+1ans[i][j]=ans[i][j−1]
3、dp[i−1][j]==dp[i][j−1]
dp[i][j]=dp[i][j−1]+1ans[i][j]=ans[i−1][j]+ans[i][j−1]
这个方案书状态转移方程式在构造最短序列的过程中进行的,当a[i] == b[i]的时候,同理上个方法,不一样时,dp[i−1][j]<dp[i][j−1] ,肯定要选一个最小的,就是dp[i−1][j],所以就舍弃了dp[i][j−1] 这种排列,所以ans[i][j]=ans[i−1][j] ,同理下一个,当dp[i−1][j]==dp[i][j−1] 时,这个位置,选i也行,选j也行,这就是两种情况了。。
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;typedef long long LL;char s1[50],s2[50];int n,m,f[50][50];LL dp[50][50];int main(){ int i,j,cas,T; scanf("%d",&cas); for(T = 1;T <= cas;T++){ scanf("%s%s",s1+1,s2+1); n = strlen(s1+1);m = strlen(s2+1); memset(dp,0,sizeof(dp)); memset(f,0,sizeof(f)); for(i = 0;i <= n;i++) f[i][0] = i,dp[i][0] = 1; for(j = 0;j <= m;j++) f[0][j] = j,dp[0][j] = 1; for(i = 1;i <= n;i++){ for(j = 1;j <= m;j++){ if(s1[i]==s2[j]){ f[i][j] = f[i-1][j-1]+1; dp[i][j] = dp[i-1][j-1]; }else{ f[i][j] = min(f[i-1][j],f[i][j-1])+1; if(f[i-1][j]<=f[i][j-1]) dp[i][j] += dp[i-1][j]; if(f[i-1][j]>=f[i][j-1]) dp[i][j] += dp[i][j-1]; } } } printf("Case %d: %d %lld\n",T,f[n][m],dp[n][m]); } return 0;}
法三:
解题思路:字符串的最短长度就是两个字符串的长度和-LCS(两个字符串)
接着是求这个字符串有多少种组成方式了
用ans[i][j][k]表示该字符串当前有i个字符,包含了第一个字符串的j个字符,第2个字符串的k个字符的种类数
如果s1[j] = s2[k]
ans[i + 1][j + 1][k + 1] += ans[i][j][k]
如果s1[j] != s2[k]
ans[i + 1][j][k + 1] += ans[i][j][k]
ans[i + 1][j + 1][k] += ans[i][j][k]
这个状态转移跟法一其实是一样的,只不过这个是向后面转移,当s1[j] = s2[k] 时,ans[i + 1][j + 1][k + 1] += ans[i][j][k] ,si+1跟sj+1都是一样的,没有选择
如果s1[j] != s2[k] ,ans[i + 1][j][k + 1] += ans[i][j][k] ,也就是说他把第i+1个设成是sj的情况,同理ans[i + 1][j + 1][k] += ans[i][j][k]
#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int N = 35;char s1[N], s2[N];int len1, len2, cas = 1;int dp[N][N];long long ans[N * 2][N][N];void init() { scanf("%s%s", s1 + 1, s2 + 1); len1 = strlen(s1 + 1); len2 = strlen(s2 + 1);}int LCS() { memset(dp, 0, sizeof(dp)); for (int i = 1; i <= len1; i++) for (int j = 1; j <= len2; j++) { if (s1[i] == s2[j]) dp[i][j] = dp[i - 1][j - 1] + 1; else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); } return dp[len1][len2];}void solve() { int len = len1 + len2 - LCS(); memset(ans, 0, sizeof(ans)); ans[0][0][0] = 1; for (int i = 0; i <= len; i++) for (int j = 0; j <= len1; j++) for (int k = 0; k <= len2; k++) if (ans[i][j][k]) { if (s1[j + 1] == s2[k + 1]) ans[i + 1][j + 1][k + 1] += ans[i][j][k]; else { ans[i + 1][j][k + 1] += ans[i][j][k]; ans[i + 1][j + 1][k] += ans[i][j][k]; } } printf("Case %d: %d %lld\n", cas++, len, ans[len][len1][len2]);}int main() { int test; scanf("%d", &test); while (test--) { init(); solve(); } return 0;}
这么多种转移方程,我竟然一个也没想到,只想到组合数学xjb乱搞。。dp还是被虐的少了啊
- ☆lightoj1013 Love Calculator 两种转移方程详解(LCS+方案数DP)
- LightOJ1013---Love Calculator (dp)
- LightOJ1013-Love Calculator-dp
- LightOJ 1013 - Love Calculator (LCS + dp)
- 【LightOJ 1013】Love Calculator(LCS+DP)
- lightoj 1013 Love Calculator (LCS+dp)
- Light OJ 1013 - Love Calculator(LCS+ 计方案数)
- LightOJ 1013 Love Calculator 【DP(LCS变形)】
- LightOJ 1013 Love Calculator (LCS+DP)
- LightOJ - 1013 Love Calculator(LCS + DP)
- LightOJ-1013-Love Calculator [LCS][DP]
- LightOJ 1013 Love Calculator(LCS)
- LightOJ 1013 - Love Calculator(LCS)
- LightOJ 1013 - Love Calculator(DP)
- LightOJ 1013 - Love Calculator(dp)
- light Oj 1013 - Love Calculator (dp)
- lightoj 1013 - Love Calculator 【LCS 变形】
- DP入门,数塔,核心是状态转移方程
- 点击事件(v-on:click)
- 欢迎使用CSDN-markdown编辑器
- haproxy的安装与配置
- 如何重置win10网络连接名称或计数
- CCIE学习笔记框架——网络的初步了解
- ☆lightoj1013 Love Calculator 两种转移方程详解(LCS+方案数DP)
- 浅谈被加壳ELF(即android的so文件)的调试
- mybatis笔记1
- SpringMVC整合Tiles框架
- mvp
- hadoop decommission 非常慢的问题
- private 含糊的私有成员
- json_encode 中文乱码
- 设计模式之四:模板方法模式