[DP_LCS] UVA10723

研究了好久,也没怎么明白…
对DP的理解真的不够….只能勉强记住已经知道的题型


放个别人的解析,感觉是写的最全的了

我们可以模仿LCS的构建方法来思考这个问题 c[i][j]表示a串前i个元素和b串前j个元素所能得到的方案数。l[i][j]表示LCS的长度

若a[i]=b[j],那么c[i][j]=c[i-1][j-1],即a串前i-1个元素和b串前j-1个元素得到的组合串的末尾加上一个相同的元素a[i],那么得到的新的组合串的个数还是和之前的组合串的个数一样

若a[i]!=b[j], l[i][j]=max { l[i-1][j] , l[i][j-1]}

若l[i-1][j]>l[i][j-1],那说明从l[i-1][j]这种状态开始构建才能得到最终的LCS同时最终的组合串才不能漏掉共有的元素,所以c[i][i]=c[i-1][j],即在a串i-1个元素和b串j个元素组成的组合串的后面加上a[i],那么得到的新的组合串的个数和之前的组合串的个数是相同的

若l[i][j-1]>l[i-1][j],道理和上面是一样的,所以c[i][j]=c[i][j-1],相当于在之前的组合串后面加上元素b[j],得到新的组合串的个数不变

若l[i][j-1]=l[i-1][j],说明从两种状态都是能得到最终的LCS并且最终的组合串不会漏掉任何相同的公共元素,所以c[i][j]=c[i-1][j]+c[i][j-1] , 即用a串的i-1个元素和b串的j个元素组成的组合串的最后加上a[i]得到新的组合串和之前的组合串个数相同,另外用a串的i个元素和b串的的j-1个元素组成的组合串的最后加上b[j]得到新的组合串和之前的组合串个数相同,那么就是两者之和(http://www.cnblogs.com/scau20110726/archive/2012/10/01/2709781.html)




剩下的就是注意空行
gets已经不能用了所以getline


问了一个大佬
大佬直接就看出是DP
然后举了一个例子归纳就得出了状态转移方程。。。。。
这或许就是大佬吧.jpg


#include <cstdio>
#include <cstring>
#include <iostream>

#define N 50

char str1[ N ];
char str2[ N ];
int len1, len2;

int length[ N ][ N ];
long long variety[ N ][ N ];

int main () {
        int T;
        scanf ( "%d", &T );
        getchar ();
        for ( int t = 1; t <= T; t++ ) {
                std::cin.getline ( str1 + 1, N - 1 );
                std::cin.getline ( str2 + 1, N - 1 );

                len1 = strlen ( str1 + 1 );
                len2 = strlen ( str2 + 1 );

                memset ( length, 0, sizeof ( length ) );
                memset ( variety, 0, sizeof ( variety ) );
                for ( int i = 0; i <= len1; i++ )
                        variety[ i ][ 0 ] = 1;
                for ( int i = 0; i <= len2; i++ )
                        variety[ 0 ][ i ] = 1;

                for ( int i = 1; i <= len1; i++ ) {
                        for ( int j = 1; j <= len2; j++ ) {

                                if ( str1[ i ] == str2[ j ] ) {
                                        length[ i ][ j ] = length[ i - 1 ][ j - 1 ] + 1;
                                        variety[ i ][ j ] = variety[ i - 1 ][ j - 1 ];
                                }

                                else {
                                        if ( length[ i - 1 ][ j ] > length[ i ][ j - 1 ] ) {
                                                length[ i ][ j ] = length[ i - 1 ][ j ];
                                                variety[ i ][ j ] = variety[ i - 1 ][ j ];
                                        } else if ( length[ i - 1 ][ j ] == length[ i ][ j - 1 ] ) {
                                                length[ i ][ j ] = length[ i - 1 ][ j ];
                                                variety[ i ][ j ] =
                                                    variety[ i - 1 ][ j ] + variety[ i ][ j - 1 ];
                                        } else {
                                                length[ i ][ j ] = length[ i ][ j - 1 ];
                                                variety[ i ][ j ] = variety[ i ][ j - 1 ];
                                        }
                                }
                        }
                }
                printf ( "Case #%d: %d %lld\n", t, len1 + len2 - length[ len1 ][ len2 ],
                         variety[ len1 ][ len2 ] );
        }
        return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值