CodeForces - 946D Timetable (分组背包+思维)

题意

n天的课程,每天有m个时间单位.若时间i和j都有课,那么要在学校待\(j-i+1\)个时间.现在最多能翘k节课,问最少能在学校待多少时间.

分析

将一天的内容视作一个背包的组,可以预处理出该天内翘k节课能得到的最多空闲时间.\(val[i][k]\)表示第i天中翘k节课能够获取最多的时间,暴力枚举左右分别翘\(p\)\(k-p\)节课,取最大值.这样相当于得到了每个组内的物品重量(翘的课数)和价值(得到的空闲时间).再做一次分组背包求出能获得的最大空闲时间,用总的时间减去得到最少要待在学校的时间.

#include<bits/stdc++.h>
#define PII pair<int,int>
#define MP make_pair
#define X first
#define Y second
using namespace std;
const int maxn = 1e3+5;
const int INF = 0x3f3f3f3f;
char str[maxn];

vector<int> pos[maxn];
int val[maxn][maxn], dp[maxn][maxn];

int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
        freopen("out.txt", "w", stdout);
    #endif
    int n, m ,W;
    scanf("%d %d %d",&n, &m, &W);

    for(int i=1;i<=n;++i){
        scanf("%s",str+1);
        for(int j=1; j<=m; ++j){
            if(str[j]=='1') pos[i].push_back(j);
        }
    }

    for(int i = 1;i<=n; ++i){
        int sz = pos[i].size();
        if(sz==0) {
            val[i][0] = m;
            continue;
        }
        for(int j = 0; j <= min(W,sz); ++j){
            int cnt = INF;
            if(j==sz){
                val[i][sz] = m;
                break;
            }
            for(int L = 0, R; L <= j; ++L ){
                R = sz - (j - L) - 1;
                cnt = min(cnt,pos[i][R] - pos[i][L]+1);
            }
            val[i][j] = m - cnt;
        }
    }
    for(int i = 1; i <= n ;++i){
        int sz = pos[i].size();
        for(int k = 0; k <= sz;++k){
            for(int j = W; j>= k; --j){
                dp[i][j] = max(dp[i][j], dp[i-1][j-k]+ val[i][k]);
            }
        }
    }
    printf("%d\n",n*m-dp[n][W]);
    return 0;
}

posted @ 2018-10-23 13:08  xiuwenL  阅读(189)  评论(0编辑  收藏  举报