CF946D Timetable(动态规划)

Timetable

题意:

给出 nm01 串,对于每一行所要花费的代价是行中第一个 1 和最后一个 1 之间的距离加一,现在你有魔法可以去除掉 k1,问去掉不多于 k1 的情况下,你所能获得的最小代价是多少。

思路:

看到有 k 次限制求最小代价,不难想到需要用到 DP 来解决,不妨考虑设状态 dp[i][j] 表示在前 i 个串中逃了 j 次课最少的上课时间是多少。那么就可以将逃了多少次课视作一个物品的容量,每一天上课的时间看作是物品的价值,这样就转化成了一个背包问题。但是每一天到底哪些课要逃,哪些课不逃不太好处理,所以需要对每一天做一个预处理。
定义一个数组 v[i][j] 表示第 i 天翘了 j 节课的最小代价,因为题目说了,一天的在校时间是最后一节课的时间减去第一节课的时间,所以只有逃首尾两端的课才可以让贡献变小,那么只需要去 O(n2) 的循环计算一下中间要上哪些课就可以了

memset(v, 0x3f, sizeof v); for (int i = 1; i <= n; i++) { string s; cin >> s; int len = 0; for (int j = 0; j < m; j++) { if (s[j] & 1) a[++len] = j + 1; //记录哪些时间段有课 } v[i][len] = 0; siz[i] = len; for (int j = 1; j <= len; j++) for (int k = j; k <= len; k++) v[i][len - (k - j + 1)] = min(v[i][len - (k - j + 1)], a[k] - a[j] + 1); //中间要上课的时间 }

之后就是一个基础的背包转移

memset(dp, 0x3f, sizeof dp); for (int i = 0; i <= p; i++) dp[0][i] = 0; for (int i = 1; i <= n; i++) { for (int j = 0; j <= p; j++) { for (int k = 0; k <= min(j, siz[i]); k++) { dp[i][j] = min(dp[i][j], dp[i - 1][j - k] + v[i][k]); } } } printf("%d\n", dp[n][p]);

__EOF__

本文作者HoneyGrey
本文链接https://www.cnblogs.com/Haven-/p/17058896.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   浅渊  阅读(43)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示