Bootstrap

【c++笔试强训】(第四十七篇)

目录

活动安排(贪⼼-区间)

题目解析

讲解算法原理

编写代码

合唱团(动态规划-线性dp)

题目解析

讲解算法原理

编写代码


活动安排(贪⼼-区间)

题目解析

1.题目链接:活动安排_牛客题霸_牛客网

2.题目描述

描述

给定nn个活动,每个活动安排的时间为[a_i,b_i)[ai​,bi​)。求最多可以选择多少个活动,满足选择的活动时间两两之间没有重合。

输入描述:

第一行输入一个整数nn (1\le n \le 2 \cdot 10^51≤n≤2⋅105),表示可选活动个数。
接下来的nn行,每行输入两个整数a_i,b_iai​,bi​ (0\le a_i < b_i \le 10^90≤ai​<bi​≤109),表示第ii个活动的时间。

输出描述:

输出一行一个整数,表示最多可选择的活动数。

示例1

输入:

3
1 4
1 3
3 5

复制输出:

2

讲解算法原理

解法:
算法思路:

区间问题的贪⼼:排序,然后分情况讨论,看看是合并还是求交集

编写代码

c++算法代码:

#include <iostream>
#include <algorithm>
using namespace std;
typedef pair<int, int> PII;
const int N = 2e5 + 10;
int n;
PII arr[N];
int main()
{
 cin >> n;
 for(int i = 0; i < n; i++) cin >> arr[i].first >> arr[i].second; sort(arr, arr + n);
 int ret = 0, r = arr[0].second; for(int i = 1; i < n; i++) {
 if(arr[i].first < r) // 有重叠 {
 r = min(r, arr[i].second);
 }
 else // 没有重叠 {
 ret++;
 r = arr[i].second;
 }
 }
 cout << ret + 1 << endl;
 return 0;
}

java算法代码:

import java.util.*;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main
{
 public static void main(String[] args) 
 {
 Scanner in = new Scanner(System.in); int n = in.nextInt(); int[][] arr = new int[n][2]; for(int i = 0; i < n; i++)
 {
 arr[i][0] = in.nextInt(); arr[i][1] = in.nextInt(); }
 Arrays.sort(arr, (a, b) -> 
 {
 return a[0] <= b[0] ? -1 : 1;
 });
 int ret = 0, r = arr[0][1]; for(int i = 1; i < n; i++) {
 if(arr[i][0] < r) // 有重叠 {
 r = Math.min(r, arr[i][1]);
 }
 else // 没有重叠 {
 ret++; r = arr[i][1]; }
 }
 System.out.println(ret + 1);
 }
}

合唱团(动态规划-线性dp)

题目解析

1.题目链接:合唱团_牛客题霸_牛客网

2.题目描述

描述

有 n 个学生站成一排,每个学生有一个能力值,牛牛想从这 n 个学生中按照顺序选取 k 名学生,要求相邻两个学生的位置编号的差不超过 d,使得这 k 个学生的能力值的乘积最大,你能返回最大的乘积吗?

输入描述:

每个输入包含 1 个测试用例。每个测试数据的第一行包含一个整数 n (1 <= n <= 50),表示学生的个数,接下来的一行,包含 n 个整数,按顺序表示每个学生的能力值 ai(-50 <= ai <= 50)。接下来的一行包含两个整数,k 和 d (1 <= k <= 10, 1 <= d <= 50)。

输出描述:

输出一行表示最大的乘积。

示例1

输入:

3
7 4 7
2 50

复制输出:

49

讲解算法原理

解法:
算法思路:

线性dp。

编写代码

c++算法代码:

#include <iostream>
using namespace std;
typedef long long LL;
const int N = 55, M = 15;const LL INF = 0x3f3f3f3f3f3f3f3f;
int n, k, d;
LL arr[N];
LL f[N][M], g[N][M];
int main()
{
 cin >> n;
 for(int i = 1; i <= n; i++) cin >> arr[i]; cin >> k >> d;
 // 初始化放在填表中进⾏了
 for(int i = 1; i <= n; i++) // 填写每⼀⾏ {
 g[i][1] = f[i][1] = arr[i];
 for(int j = 2; j <= min(i, k); j++) // 挑选⼏个⼈ {
 f[i][j] = -INF; // 初始化
 g[i][j] = INF; // 初始化
 for(int prev = max(i - d, j - 1); prev <= i - 1; prev++) // 前⾯挑选
的最后⼀个位置 {
 f[i][j] = max(max(f[prev][j - 1] * arr[i], g[prev][j - 1] * arr[i]), f[i][j]); g[i][j] = min(min(f[prev][j - 1] * arr[i], g[prev][j - 1] * arr[i]), g[i][j]); }
 }
 }
 LL ret = -INF;
 for(int i = k; i <= n; i++) ret = max(ret, f[i][k]); cout << ret << endl;
 return 0;
}

java算法代码:

import java.util.*;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main
{
 public static int N = 55, M = 15;
 // public static long INF = 0x3f3f3f3f3f3f3f3f; // 报错
 public static int n, k, d; public static long[] arr = new long[N]; public static long[][] f = new long[N][M]; public static long[][] g = new long[N][M];
 public static void main(String[] args) 
 {
 Scanner in = new Scanner(System.in); n = in.nextInt(); for(int i = 1; i <= n; i++)  { arr[i] = in.nextLong();
 }
 k = in.nextInt(); d = in.nextInt();
 // 初始化放在填表中进⾏
 for(int i = 1; i <= n; i++) // 填写每⼀⾏ {
 f[i][1] = g[i][1] = arr[i];
 for(int j = 2; j <= Math.min(k, i); j++) // 挑选 j 个⼈ {
 f[i][j] = Long.MIN_VALUE; // 初始化
 g[i][j] = Long.MAX_VALUE; // 初始化
 for(int prev = Math.max(i - d, j - 1); prev <= i - 1; prev++)
 {
 f[i][j] = Math.max(Math.max(f[prev][j - 1] * arr[i], g[prev][j - 1] * arr[i]), f[i][j]); g[i][j] = Math.min(Math.min(f[prev][j - 1] * arr[i], g[prev][j - 1] * arr[i]), g[i][j]); }
 }
 }
 long ret = Long.MIN_VALUE; for(int i = k; i <= n; i++) ret = Math.max(ret, f[i][k]);
 System.out.println(ret);
 }
}

;