【LDUOJ】寒假专题训练——贪心EG题解

简介: 题意:给出若干个零件,每个零件都有两个属性,长度L和重量W,要对零件进行分组,每组中每个零件的长度 L 和重量 W 都能排成一个长度和重量都不下降(若i<j,则Li≤Lj,Wi ≤ Wj)的序列,求解最少的分组长度和重量均不超过10000给n个物品进行分组,对于同一组中这一组里的零件可以排序成单调不减的情况下比如:重量 1 2 3 4对应的长度是 123 123 456 678

星星之火,可以燎原


G题 最佳游览线路


附上一张从洛谷复制来的图片

微信图片_20220607180557.jpg


题意:


对于每一条旅行街(绿色线条),只可以从西边走到东边

而对于绿化道,可以选择从北向南,也可以选择从南向北,方向不限

对于旅行街,每走一段都会获得一个权值-100到100的整数

比如说我走下图中紫色箭头指向的这一条段街道,我将会获得一个权值 -42

微信图片_20220607180643.png


注意:可以从任一个路口开始游览,在任一个路口结束游览

所有权值不可能全为负

浏览的部分应该是连续的


贪心的策略:


挑选每一列中最大的那个数,选择最大权值的那一段街道进行浏览

但是有个问题,如果说浏览了某一段之后,到目前为止的总和是负数,那么我可以直接抛弃这一段,因为前面的这一段负数可能会降低我最终答案的值,成为最终答案的“累赘”


所以代码也是非常的简单 心不慌,手不抖,代码跟着思路走

提前预处理出每一列的最大值

然后再从这些最大值中选取一段连续的,一直取max

如果加上某个权值之后,导致sum < 0 ,直接放弃前面的一段(前面可能会有的贡献已经被记录在max中)


代码


/*** keep hungry and calm PushyTao!***/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int m,n;
int a[107][20007];
int b[20007];
int main() {
  int m,n;
  cin >> m >> n;
  for(int i=1; i<=m; i++) {
    for(int j=1; j<=n; j++) {
      scanf("%d",&a[i][j]);
    }
  }
  int sum = 0;
  int ans = 0;
  for(int i=1; i<=n; i++) {
    int mx = -200;
    for(int j=1; j<=m; j++) {
      mx = max(mx,a[j][i]);
    }
    b[i] = mx;///每列的最大值 
  }
  for(int i=1;i<=n;i++){
    sum += b[i];
    if(sum < 0) sum = 0;///如果说加上这个权值之后,总获得的权值甚至 <0 ,那就考虑将前面的那一段不考虑,sum赋值为0
    ans = max(ans,sum); 
  }
  cout<< ans <<endl;
  return 0;
}
/**
3 5 
-50 -47 36 -30 -23 
17 -19 -34 -13 -8 
-42 -3 -43 34 -45
**/


E题 零件分组


题意:


给出若干个零件,每个零件都有两个属性,长度L和重量W,要对零件进行分组,每组中每个零件的长度 L 和重量 W 都能排成一个长度和重量都不下降(若i<j,则Li≤Lj,Wi ≤ Wj)的序列,求解最少的分组

长度和重量均不超过10000

给n个物品进行分组,对于同一组中

这一组里的零件可以排序成单调不减的情况下

比如:

重量 1 2 3 4

对应的长度是 123 123 456 678


思路:


首先长度和重量两个变量,同时考虑不好处理,所以就对其中的长度进行从小到大进行排序,如果长度相同的话按照重量从小到大进行排序,首先让长度满足不下降这种状态,然后其余的只考虑重量就好

情况①某一个零件的重量小于某一组的最后面零件的重量,就要放在其他满足题意的分组,或者重新建立一个分组放入

情况②一个零件的重量大于某一组最后面零件的重量,可不可以直接放入?答案是不一定

假如进行到下面这种情况:

微信图片_20220607181125.png


第一组有【1,2】和【3,4】

第二组最后面是【4,7】

如果未分组的【6,7】放到第一个分组的话,后面的【7,5】就没有办法放到第二个分组(因为重量5小于第二组最后面零件的重量),这时候就要重新建立一个分组,要用到三个组

但是如果将【6,7】放到第二个分组,那么后面的【7,5】就可以顺其自然的放到第一个分组

此时答案是2,

以上两种放置的方法显然是第二种方法更优


所以对于情况②贪心的策略就是每次添加的时候,添加到某一组最后一个零件重量和要添加的这个零件的重量最接近的那一组的后面

注意:不理解可以联想一下当时讲过的活动安排问题,在这里重量越接近,后面可能容纳零件得就可能越多


在写代码的时候,可以用一个数组标记一下每一组最后面的零件的重量,如果是某一组最后面零件的重量,设为true,否则设为false

(比如重量6是某一组最后面零件的重量,那么hava[6] = true,反之标记hava[6] = false)


上面已经提到,每次添加的时候,添加到某一组最后一个零件重量和要添加的这个零件的重量最接近的那一组的后面,那么应该怎么找到这一组呢?

=> 可以这样来想,因为想要找的那个重量一定是小于等于当前的重量,所以就可以从当前重量到1进行遍历,如果说遇到前面提到hava[j] == true,那么这一组就一定是最优的,然后将这个重量标记为false,将这一组最后面零件的重量标记为刚加入的零件的重量(have[j] = false,hava[a[i].w] = true)


当然很容易想到,因为重量最大是10000,那么我在最后进行遍历的时候,如果说这个为true,那么就是某一组的最后面的零件,就是一个组,统计有多少个标记即为最终有多少个组,就是答案


代码:


(当然会有更优的方法~)

/*** keep hungry and calm PushyTao!***/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct Node {
  int l;
  int w;
} a[1007];
bool cmp(Node a,Node b) {
  if(a.l != b.l) return a.l < b.l;
  else return a.w < b.w;
}
bool have[10007];
int main() {
  int n;
  cin >> n;
  for(int i=1; i<=n; i++) {
    scanf("%d",&a[i].l);
    scanf("%d",&a[i].w);
  }
  sort(a + 1,a + 1 + n,cmp);
  for(int i=1; i<=n; i++) {///遍历n个零件
      /**
      长度和重量均为不超过10000的正整数
        倒着向前寻找此时如果存在就是和这个零件最接近的
      **/
    for(int j=a[i].w; j>=1; j--) {
      if(have[j]) {
        have[j]  = false;///因为要替换掉,所以这个重量就不再是最后面的那一个零件的重量,设置为false
        break;///结束循环
      }
    }
    have[a[i].w] = true;///此时这个零件就是某一组最后面的一个零件,标记为true
  }
  int ans = 0;
  for(int i=1; i<=10000; i++) {
    if(have[i]) ans ++;///有多少个标记就是有多少个几组
  }
  printf("%d\n",ans);
  return 0;
}
/**
5
8 4 3 8 2 3 9 7 3 5
->2
**/


文章知识点与官方知识档案匹配,可进一步学习相关知识

算法技能树leetcode-贪心122-买卖股票的最佳时机 II7586 人正在系统学习中


目录
相关文章
|
7月前
|
算法 测试技术 C++
【动态规划】C++ 算法458:可怜的小猪
【动态规划】C++ 算法458:可怜的小猪
|
4月前
|
算法 Java 测试技术
算法设计(动态规划实验报告) 基于动态规划的背包问题、Warshall算法和Floyd算法
这篇文章介绍了基于动态规划法的三种算法:解决背包问题的递归和自底向上实现、Warshall算法和Floyd算法,并提供了它们的伪代码、Java源代码实现以及时间效率分析。
算法设计(动态规划实验报告) 基于动态规划的背包问题、Warshall算法和Floyd算法
|
5月前
|
算法 Java C语言
刷题训练之双指针问题
刷题训练之双指针问题
33 0
|
6月前
|
机器人
【LeetCode】--- 动态规划 集训(二)
【LeetCode】--- 动态规划 集训(二)
39 0
|
6月前
【LeetCode】--- 动态规划 集训(一)
【LeetCode】--- 动态规划 集训(一)
36 0
|
存储 算法
每日一题,贪心算法的简单应用
每日一题,贪心算法的简单应用
|
机器学习/深度学习 存储 自然语言处理
牛客竞赛每日俩题 - 动态规划1
牛客竞赛每日俩题 - 动态规划1
[算法刷题题解笔记] 洛谷 P1007 独木桥 [贪心]
[算法刷题题解笔记] 洛谷 P1007 独木桥 [贪心]
|
JavaScript
牛客竞赛每日俩题 - 动态规划3
牛客竞赛每日俩题 - 动态规划3
|
存储 Windows
牛客竞赛每日俩题 - 动态规划4
牛客竞赛每日俩题 - 动态规划4