946D. Timetable

传送门

预处理加分组背包

n行m列,每列的花费是第一个与最后一个1的构成的区间长度,已知可以去除不多于k个1,求最小花费

#include <map>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e6 + 10;
int n, m, k;

int A[510];
int cst[510][510];
int dp[510][510];

int main() {
    memset(cst, INF, sizeof(cst));
    memset(dp, INF, sizeof(dp));
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 1; i <= n; i++) {
        A[0] = 0;
        int tmp;
        for (int j = 1; j <= m; j++) {
            scanf("%1d", &tmp);
            if (tmp == 1) {
                A[++A[0]] = j;
            }
        }
        cst[i][0] = A[0] == 0 ? 0 : A[A[0]] - A[1] + 1;
        for (int j = 1; j < A[0]; j++) {
            for (int kk = 1; kk <= j + 1; kk++) {
                cst[i][j] = min(cst[i][j], A[A[0] - (j - kk + 1)] - A[kk] + 1);
            }
        }
        for (int j = A[0]; j <= k; j++) cst[i][j] = 0;
    }
    dp[0][0] = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= k; j++) {
            for (int kk = 0; kk <= j; kk++) {
                dp[i][j] = min(dp[i][j], dp[i - 1][j - kk] + cst[i][kk]);
            }                
        }
    }
    printf("%d
", dp[n][k]);
    return 0;
}
原文地址:https://www.cnblogs.com/xFANx/p/8667242.html