CF 225C Barcode dp

博客探讨了一个字符矩阵的问题,要求将每列变成相同字符,目标是找到使连续列相同字符长度在x和y之间的最小代价。通过转换矩阵为两个长度为列数的数组简化问题,然后应用动态规划求解。新字符的转移条件是与前一个字符相同或者前一串字符长度达到x但不超过y。此外,介绍了一种处理初始状态的方法,即先手动计算第一个状态,再从第二个状态开始迭代。
摘要由CSDN通过智能技术生成

给出一个字符矩阵, 现在把每一列变成相同的字符, 问使得连续列都是相同字符的长度>=x且<=y的最小花费是多少.

考虑这个字符矩阵的行是没有真实作用的. 其实就是将这个字符矩阵换为两个长度为列数的数组, 此后就是简单的dp了.

新字符如果和前面相同, 转移;

新字符和前面不同, 只有当前面的字符连续个数达到x个(当然也要小于y)才能转移.

新知识: 如果实在不知道初态怎么设, 可以先将第一个(dp[1])手动算出, 然后循环中从2开始就好了.

#include<bits/stdc++.h>

#define enter puts("")
using namespace std;

typedef long long ll;

inline ll read() {
    ll x = 0;
    int f = 0;
    char ch = getchar();
    while (ch < '0' || ch > '9') f |= (ch == '-'), ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x = f ? -x : x;
}

inline void write(ll x) {
    if (x == 0) {
        putchar('0');
        return;
    }
    if (x < 0) {
        putchar('-');
        x = -x;
    }
    static char s[23];
    int l = 0;
    while (x != 0)s[l++] = x % 10 + 48, x /= 10;
    while (l)putchar(s[--l]);
}

template<class T, class U>
inline void checkMin(T &x, U y) { if (y < x) x = y; }

const int inf = 0x3f3f3f3f;

// HAVE FREE OPEN IN MAIN FUNCTION

int n, m, x, y;
int dp[1005][1005][2];
//       i     j   k
//  k表示.还是#
// 到第i位k类延续了j列.

char a[1005][1005];
int p[1005];
int q[1005];

void init() {
    n = read(), m = read(), x = read(), y = read();
    for (int i = 0; i < n; i++) {
        scanf("%s", a[i]);
    }
    for (int j = 0; j < m; ++j) {
        int cnt = 0;
        for (int i = 0; i < n; ++i) {
            if (a[i][j] == '.')cnt++;
        }
        p[j + 1] = cnt;
        q[j + 1] = n - cnt;
    }
//    for (int l = 1; l <= m; ++l) {
//        printf("%d %d\n", p[l], q[l]);
//    }
    fill(dp[0][0], dp[0][0] + 1005 * 1005 * 2, inf);
    dp[1][1][1] = q[1];
    dp[1][1][0] = p[1];
    for (int i = 2; i <= m; ++i) {
        for (int j = 1; j <= min(y, i); ++j) {
            checkMin(dp[i][j][1], dp[i - 1][j - 1][1] + q[i]);
            if (j >= x)checkMin(dp[i][1][1], dp[i - 1][j][0] + q[i]);
            checkMin(dp[i][j][0], dp[i - 1][j - 1][0] + p[i]);
            if (j >= x)checkMin(dp[i][1][0], dp[i - 1][j][1] + p[i]);
        }
    }
    int ans = inf;
    for (int k = x; k <= y; ++k) {
        checkMin(ans, dp[m][k][0]);
    }
    for (int k = x; k <= y; ++k) {
        checkMin(ans, dp[m][k][1]);
    }
    write(ans);
    enter;
}

void solve() {

}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    init();

    solve();

    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值