uva1625(颜色的长度),类似lcs的dp

题面

uva1625题面

题意

在这里插入图片描述

思路

这是一道紫书上面的动态规划题,一直想不到思路,过了两天看书后面的题解,豁然开朗,用 d [ i ] [ j ] d[i][j] d[i][j]表示取前i个s的元素和前j个t的元素时的最小代价,显然只能由 d [ i ] [ j − 1 ] 和 d [ i − 1 ] [ j ] d[i][j-1]和d[i-1][j] d[i][j1]d[i1][j]转移得到,由 d [ i ] [ j − 1 ] d[i][j-1] d[i][j1]转移,代价为 c n t [ i ] [ j − 1 ] cnt[i][j-1] cnt[i][j1](取s的前i个元素和t的前j个元素时,已经出现且未结束的元素个数),由 d [ i − 1 ] [ j ] d[i-1][j] d[i1][j]转移也同理。
所以得到状态转移方程:
d [ i ] [ j ] = m i n ( d [ i ] [ j − 1 ] + c n t [ i ] [ j − 1 ] , d [ i − 1 ] [ j ] + c n t [ i − 1 ] [ j ] ) d[i][j]=min(d[i][j-1]+cnt[i][j-1],d[i-1][j]+cnt[i-1][j]) d[i][j]=min(d[i][j1]+cnt[i][j1],d[i1][j]+cnt[i1][j])
现在就是要解决如何求 c n t [ i ] [ j ] cnt[i][j] cnt[i][j]
代码如下
预处理(记录元素在s,t里面的开始和终止位置)

       for (int i = 1; i <= lens; i++)
        {
            int cur = s[i] - 'A';
            ss[cur] = min(ss[cur], i);
            es[cur] = i;
        }
        for (int i = 1; i <= lent; i++)
        {
            int cur = t[i] - 'A';
            st[cur] = min(st[cur], i);
            et[cur] = i;
        }

c n t [ i ] [ j ] cnt[i][j] cnt[i][j]

               if (i)//其实从从c[i-1][j]和c[i][j-1]转移都一样,只是0要特判
                {
                    cnt[i][j] = cnt[i - 1][j];
                    if (ss[s[i] - 'A'] == i && st[s[i] - 'A'] > j)
                        cnt[i][j]++;
                    if (es[s[i] - 'A'] == i && et[s[i] - 'A'] <= j)
                        cnt[i][j]--;
                }
                else if (j)
                {
                    cnt[i][j] = cnt[i][j - 1];
                    if (st[t[j] - 'A'] == j && ss[t[j] - 'A'] > i)
                        cnt[i][j]++;
                    if (et[t[j] - 'A'] == j && es[t[j] - 'A'] <= i)
                        cnt[i][j]--;
                }
                else if (i == 0 && j == 0)
                    cnt[i][j] = 0;

一开始以为这个代码在由元素只出现一次时会有bug,其实不会,如果有元素只出现一次,一定会执行cnt++和cnt–,相当于不变,还有 d [ i ] [ j ] d[i][j] d[i][j]并不是真正取s前i个t前j个的最小代价,而是取s前i个t前j个并且默认在最后一个元素所以元素都终止的代价,这个需要思考一波。

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 5100;
const int inf = 0x3f3f3f3f;
int d[maxn][maxn], cnt[maxn][maxn];
int ss[30], st[30], es[30], et[30];
int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        char s[maxn], t[maxn];
        scanf("%s%s", s + 1, t + 1);
        int lens = strlen(s + 1);
        int lent = strlen(t + 1);
        memset(ss, inf, sizeof(ss));
        memset(st, inf, sizeof(st));
        memset(es, 0, sizeof(es));
        memset(et, 0, sizeof(et));
        for (int i = 1; i <= lens; i++)
        {
            int cur = s[i] - 'A';
            ss[cur] = min(ss[cur], i);
            es[cur] = i;
        }
        for (int i = 1; i <= lent; i++)
        {
            int cur = t[i] - 'A';
            st[cur] = min(st[cur], i);
            et[cur] = i;
        }
        for (int i = 0; i <= lens; i++)
        {
            for (int j = 0; j <= lent; j++)
            {
                int u = inf, v = inf;
                if (i == 0 && j == 0)
                {
                    d[i][j] = 0;
                }
                else
                {
                    if (i)
                    {
                        u = d[i - 1][j] + cnt[i - 1][j];
                    }
                    if (j)
                    {
                        v = d[i][j - 1] + cnt[i][j - 1];
                    }
                    d[i][j] = min(u, v);
                }
                if (i)
                {
                    cnt[i][j] = cnt[i - 1][j];
                    if (ss[s[i] - 'A'] == i && st[s[i] - 'A'] > j)
                        cnt[i][j]++;
                    if (es[s[i] - 'A'] == i && et[s[i] - 'A'] <= j)
                        cnt[i][j]--;
                }
                else if (j)
                {
                    cnt[i][j] = cnt[i][j - 1];
                    if (st[t[j] - 'A'] == j && ss[t[j] - 'A'] > i)
                        cnt[i][j]++;
                    if (et[t[j] - 'A'] == j && es[t[j] - 'A'] <= i)
                        cnt[i][j]--;
                }
                else if (i == 0 && j == 0)
                    cnt[i][j] = 0;
            }
        }
        cout << d[lens][lent] << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值