紫书dp学习

/*
    Uva1625
    题意:给你两个序列A B, 每次可以从其中一个序列的头部拿出一个字符放到新序列C的末尾,定义C序列的优美度为每个字符结束位置减去开始
    位置, 现在让你最小化优美度。
    tag: dp
    分析:我们转换思维, 当从其中一个序列拿出一个放到C的末尾的时候这个字符是对答案有贡献的, 他的贡献值就是当前已经开始但未结束
    的字符的个数。 因此我们定义dp[i][j] 为A序列1 - i, B序列1 - j能构造的字符串的最少优美度, 那么dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + w[i][j]
    其中w[i][j]为当前已经开始但未结束的字符的个数。

*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>

using namespace std;
const int maxn = 5000 + 100;
char str1[maxn], str2[maxn];
int len1, len2;
int r1[30], r2[30];
int dp[maxn][maxn];

int main() {
    int T; scanf("%d", &T);
    while(T--) {
        scanf("%s%s", str1+1, str2+1);
        len1 = strlen(str1+1);  len2 = strlen(str2+1);
        memset(r1, -1, sizeof(r1));
        memset(r2, -1, sizeof(r2));
        for(int i=1; i<=len1; i++) {
            int idx = str1[i] - 'A';
            if(r1[idx] == -1) r1[idx] = i;
            else r1[idx] = max(r1[idx], i);
         }
        for(int i=1; i<=len2; i++) {
            int idx = str2[i] - 'A';
            if(r2[idx] == -1) r2[idx] = i;
            else r2[idx] = max(r2[idx], i);
        }
        set<char> st;
        dp[0][0] = 0;
        for(int i=0; i<=len1; i++){
            if(i) st.insert(str1[i]);
            set<char> tpst = st;
            for(int j=0; j<=len2; j++) {
                if(i==0 && j==0) continue;
                int tp = 0x3f3f3f3f;
                if(i-1>=0) tp = min(tp, dp[i-1][j]);
                if(j-1>=0) tp = min(tp, dp[i][j-1]);
                if(j)   tpst.insert(str2[j]);
                for(int k=0; k<26; k++) {
                    if(i>=r1[k] && j>=r2[k])
                        tpst.erase('A'+k);
                }
                dp[i][j] = tp + tpst.size();
            }
        }
        printf("%d\n", dp[len1][len2]);
    }
    return 0;
}

<pre name="code" class="cpp">/*
    Uva 10003
    题意:给你一个长度为l的棍子, 有n个切割点, 你的任务是把这个棍子切成n+1块, 使得总的切割费用最小。
    tag: dp
    分析: 我们定义dp[i][j]为切割木棍的i - j的最小费用那么dp[i][j] = min(dp[i][k] + dp[k][j] + a[j] - a[i]) .. 复杂度O(n^2)此题还有四边形不等式
    的优化方法待更。
*/
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
int l, n;
int a[100], na;
int dp[100][100];

int dfs(int l, int r) {
    if(dp[l][r] != -1) return dp[l][r];
    if(r-l == 1) return dp[l][r] = 0;
    int res = 0x3f3f3f3f;
    for(int i=l+1; i<r; i++)
        res = min(res, a[r]-a[l]+dfs(l, i)+dfs(i, r));
    return dp[l][r] = res;
}

int main() {
    while(scanf("%d", &l)==1 && l) {
        scanf("%d", &n);
        na = 0;
        a[na++] = 0;
        for(int i=1; i<=n; i++) {
           int t; scanf("%d", &t);
           a[na++] = t;
        }
        a[na++] = l;
        memset(dp, -1, sizeof(dp));
        int res = dfs(0, na-1);
        printf("The minimum cutting is %d.\n", res);
    }
    return 0;
}


 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值