D. Timetable Educational Codeforces Round 39 (Rated for Div. 2)

  • 题目链接:http://codeforces.com/contest/946/problem/D
  • 题意:设一个星期有n天,每天有m小时,给你n个长为m的字符串(由0、1组成),1表示要上课的时段。你每天需要花在学校的时间是从第一个1到最后一个1(包括头尾)。你可以翘掉最多k节课,求你一个n天总计待在学校的最小时间
  • 算法:dp
  • 思路:
    • 遍历每天
    • 用mn[i]记录当天,要上连续的i节课后所需花费的最小时间。
      • 设当天总共有len天,则 mn[len-1] 必然从 mn[len] 中取,同理 mn[len-2] 必从 mn[len-1] 中取
    • dp[i][j] 表示在前i天总共翘掉j(j不一定等于k,因为不一定需要在前i天翘完所有k节课)节课所需花的最小时间,设 i 天总共要翘掉x节课,则状态转移方程为
      • dp[i][j] = min(d[i][j], d[i-1][j-x] + mn[len-x])
      • 即在前i天翘掉总共j节课后所需花费的最小时间 = min(花费时间的最大值(即i*m)前i-1天翘掉总共j-x节课后所需花费的最小时间 + 当天上len-x节课所需花费的最小时间

#include <bits/stdc++.h>
#define pi acos(-1)
#define fastcin ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
using namespace std;
typedef long long LL;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const LL ll_INF = 0x3f3f3f3f3f3f3f3f;//4e18 ~= 2^62
const int maxn =500 + 10;
const LL mod = 1e9+7;

string s;
int loc[maxn], mn[maxn], dp[maxn][maxn];

int main()
{
    fastcin;
    int n, m, k;
    cin >> n >> m >> k;
    for(int i=1; i<=n; i++){
        cin >> s;
        int len=0;
        for(int j=0; j<s.size(); j++){
            if(s[j]=='1') loc[++len]=j;
        }
        for(int l=1; l<=len; l++){ //求mn[l]: 一天内上l节课,所需花费的最小时间
            mn[l]=m;
            for(int j=1; j<=len-l+1; j++){
                mn[l]=min(mn[l], loc[j+l-1]-loc[j]+1); // 连续的l节课呦
            }
        }
        for(int j=0; j<=k; j++){ // 前i天总共翘掉j节课
            int l;
            for(l=min(len, j), dp[i][j]=i*m; l>=0; l--){  //当天(即第i天)翘掉l节课
                dp[i][j] = min(dp[i][j], dp[i-1][j-l]+mn[len-l]);
            }
        }
    }
    cout << dp[n][k] << endl;

}

猜你喜欢

转载自blog.csdn.net/qq_37352710/article/details/79987083