P2370 yyy2015c01 的 U 盘

1|0P2370 yyy2015c01 的 U 盘

1|0基础思路

看到题目要求最小需要的最大接口。自然认为既然答案要求接口,那状态方程的值就是接口。

一开始状态方程F[i][j]i为前i个接口,j为当前体积。而F[i][j]则为当前最小的最大接口值

状态转移方程F[i][j] = min(F[i][j], (F[i - 1][j - v[i]] == INF) ? v[i] : max(F[i - 1][j - w[i]], v[i]))

然而这根本没法达到最优价值,更别提达到价值要求。

然后我又更改方程,j表示当前价值。但是这更错,首先当前价值未必最优,而且这下体积也没法保证小于U盘总体积。

冥思苦想,似乎要创造新背包算法了。

1|0改进思路

然而,我的逻辑上有一个问题,我认为DP题一定要把答案设置为状态转移方程的值

实则未必,这道题剔除最大接口后,就是一个01背包的板子。

当跑完01背包后,如何判断最大接口是问题。

这里我觉得两种做法很好。

1|0结合排序

直接先按照体积排序,这样找到答案(能装下的最大价值比要求价值大的状态)直接输出就是装入物品的最大体积,即要求的接口。

这个方法代码复杂度不高,很容易实现。但是思考复杂度还是有,比较难想到。

#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define INF 0x7fffffff using namespace std; struct yyy { int v, w; bool operator< (const yyy &rhs) const { return v < rhs.v; } }; int n, p, s; yyy a[1010]; int F[1010]; int main() { cin >> n >> p >> s; for (int i = 1; i <= n; i++) { cin >> a[i].v >> a[i].w; } sort(a + 1, a + n + 1); for (int i = 1; i <= n; i++) { for (int j = s; j >= a[i].v; j--) { F[j] = max(F[j], F[j - a[i].v] + a[i].w); if (F[j] >= p) { printf("%d", a[i].v); return 0; } } } printf("No Solution!"); return 0; }

1|0二分答案

首先看到最小的最大接口,很容易想出来可以二分答案。

思路也很明了,二分接口值,DP即可。

代码和思维都比较容易实现,就是时间复杂度可能略高。

#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define INF 0x7fffffff using namespace std; struct yyy { int v, w; bool operator< (const yyy &rhs) const { return v < rhs.v; } }; int n, p, s; yyy a[1010]; int F[1010]; bool DP(int x) { memset(F, 0, sizeof(F)); for (int i = 1; i <= n; i++) { if (a[i].v > x) continue; for (int j = s; j >= a[i].v; j--) { F[j] = max(F[j], F[j - a[i].v] + a[i].w); if (F[j] >= p) { return true; } } } return false; } int main() { cin >> n >> p >> s; for (int i = 1; i <= n; i++) { cin >> a[i].v >> a[i].w; } int l = 1, r = s, ans = 0; while (l <= r) { int mid = l + ((r - l) >> 1); if (DP(mid)) { ans = mid; r = mid - 1; } else { l = mid + 1; } } if (!ans) printf("No Solution!"); else printf("%d", ans); return 0; }

1|0总结

这题主要是战略出现了问题,以后看dp问题的时候不能只有dp,应该想想结合其他算法。状态方程也未必要和答案直接挂钩。


__EOF__

本文作者Kdlyh
本文链接https://www.cnblogs.com/kdlyh/p/17809594.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   加固文明幻景  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示