papmelon 327. 木棒 Wooden Sticks(挑战程序设计竞赛) dp
地址 https://www.papamelon.com/problem/327
由于题目有两个排序关键字长度和重量,只有两个均大于等于前一个才能达到最小费用
先尝试按照某一个关键字排序
例子中的
4 5 2 3 1
9 2 1 5 4
排序后就变成
1 2 3 4 5
4 1 5 9 2
这时候我们就发现 排序后 第二行的关键字 按照最长不下降子序列切分后 就是最小费用了
比如说
1 3 4
4 5 9
但是如何得知最后能得到最少几组最长不下降序列?
这里就涉及到Dilworth定理
Dilworth定理:
通俗解释: 把一个数列划分成最少的最长不降子序列的数目就等于这个数列的最长下降子序列的长度(LIS)。
也就是solve2的解法 直接求最长下降子序列的长度。
//=========================================
solve3 贪心解法
按照以下思路进行解答
木棒有两个关键字属性 l=长度 w=重量。 木棒已经按照l进行排序
1 在已有的不降子序列中寻找序列尾部小于等于当前木棒w的序列,该序列是寻找出的序列中尾部最大的那个,在该序列尾部插入该木棒
2 如果没有找到合适的不降子序列 则新开一个序列。
3 持续 1 2过程 直到所有木棒都插入序列 序列个数则是答案
证明贪心解就是最优解
假设贪心解不是最优解答 另有最优解
那么在最优解和贪心解 在第一个木棒插入序列不同点之后的插入序列,都可以经过有限次调整进行互换。即,贪心解与最优解可以经过有限次调整进行互换,也就是相等。
那么贪心解就是最优解。
代码见solve3
代码
#include <iostream>
#include <algorithm>
#include <memory.h>
using namespace std;
const int N = 5010;
const int INF = 9999999;
struct STICK {
int l;
int w;
}stick[N];
int n, t;
bool cmpFunc(const struct STICK& a, const struct STICK& b) {
if (a.l < b.l) return true;
else if(a.l==b.l) return a.w < b.w;
return false;
}
void solve() {
int ans = 0;
for (int i = 0; i < n; i++) {
if (stick[i].w != INF) {
int curr = -INF;
for (int j = i; j < n; j++) {
if (curr == -INF && stick[j].w != INF) {
curr = stick[j].w; ans++;
}
else if (stick[j].w != INF && curr <= stick[j].w) {
curr = stick[j].w; stick[j].w = INF;
}
}
}
}
cout << ans << endl;
return;
}
void solve2() {
int dp[N]; memset(dp, 0, sizeof dp);
dp[0] = 1;
int ans = 0;
for (int i = 1; i < n; i++) {
dp[i] = 1;
for (int j = i - 1; j >= 0; j--) {
if (stick[i].w < stick[j].w) {
dp[i] = max(dp[i], dp[j] + 1);
}
}
ans = max(ans, dp[i]);
}
cout << ans << endl;
return;
}
void solve3() {
int up[N]; int cnt = 0;
for (int i = 0; i < n; i++) {
int curr = -INF; int idx = -1;
for (int j = 0; j < cnt; j++) {
//找到up中小于等于 stick[i].w中最大的数 , 在其代表的序列中插入stick[i].w
//找不到则新建一个序列 插入stick[i].w
if (up[j] <= stick[i].w && curr < up[j]) {
idx = j; curr = up[j];
}
}
if (idx != -1) {
up[idx] = stick[i].w;
}
else {
up[cnt] = stick[i].w; cnt++;
}
}
cout << cnt << endl;
return;
}
int main()
{
cin >> t;
while (t--) {
cin >> n;
memset(stick,0,sizeof stick);
for (int i = 0; i < n; i++) {
cin >> stick[i].l >> stick[i].w;
}
sort(stick,stick+n,cmpFunc);
//solve();
//solve2();
solve3();
}
return 0;
}
欢迎转帖 请保持文本完整并注明出处
技术博客 http://www.cnblogs.com/itdef/
B站算法视频题解
https://space.bilibili.com/18508846
qq 151435887
gitee https://gitee.com/def/
欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
如果觉得不错,欢迎点赞,你的鼓励就是我的动力


【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
2020-12-02 LeetCode 048. 旋转图像
2020-12-02 LeetCode 040. 组合总和 II 非SET去重