Reach-top3819: 有手就行-->活动安排进阶(贪心,二分)

有手就行

原题请看这里

题目描述:

某天, x i n j u n xinjun xinjun邀请 i m s t r a i g h t imstraight imstraight T u n d e r Tunder Tunder _ S u n Sun Sun去吃饭。这里共有 n n n种美食,第 i i i种美食有 [ s i , e i ] [si,ei] [si,ei]的供应时间。当选择了品尝某种美食时, s i si si e i ei ei时间内只能品尝这一种美食。
x i n j u n xinjun xinjun想知道,如何安排品尝美食的顺序,能使得吃到最多种的美食。 I m s t r a i g h t Imstraight Imstraight想了想:这不是有手就行?在此基础上,不同的美食,有 t i ti ti的好吃程度,三个人想尽量吃好吃的美食。
现在, x i n j u n xinjun xinjun想知道,最多能吃到多少种美食,并且使得吃的美食中,好吃程度最低的美食好吃程度最大。 T u n d e r Tunder Tunder _ S u n Sun Sun想了想:这还是有手就行啊。

输入描述:

第一行一个正整数 T T T,代表测试数据的组数为 T T T组。
每组数据中,第一行为一个正整数 n n n,代表美食的种类。
接下来 n n n行,每行为三个正整数 s i , e i , t i s_i,e_i,t_i sieiti,分别代表美食的开始供应时间,结束供应时间和好吃程度。
其中 1 < = T < = 20 ; 1 < = n < = 100 , 000 ; 1 < = s i , e i , t i < = 2 e 9 1<=T<=20;1<=n<=100,000;1<=s_i,e_i,t_i<=2e9 1<=T<=20;1<=n<=100,000;1<=si,ei,ti<=2e9

输出描述:

每组数据输出两个正整数,这两个正整数用空格隔开,分别是最多能品尝美食的种数和所品尝的美食中好吃程度最低的值。

样例输入:

2
4
1 2 6
2 5 7
6 9 11
6 10 12
2
1 1 6
1 2 3

样例输出:

2 7
1 6

思路:

贪心+二分
如果我们不需要求最小的好吃程度最大,那么这道题就是最经典的贪心:活动安排。
所以前一个子问题就很好解决了。
再看后一个问题:求最小值最大。这不就是在明示你用二分了嘛。
于是我们二分答案,为避免二分到不是题目所给的美味程度的值,我们用一个 t m p tmp tmp数组存一下读入的美味值,二分时二分这个数组的下标,再将美味值传入 c h e c k check check里来判断是否合法,来这道题就轻松地解决了。(虽然我WA了十几遍)

AC Code:

#include  <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
struct node{int s, e, t;}a[MAXN];
int t, n, ans, cnt, tmp[MAXN];
bool cmp1 (node x, node y){
	if(x.e ^ y.e) return x.e < y.e;
	if(x.s ^ y.s) return x.s < y.s;
	return x.t > y.t;//不加也可以
}//先按结束时间排序,再按开始时间排序
int check(int mid){
	int sum = 0, st = -1;
	for(int i = 1; i <= n; ++i){
		if(a[i].t < mid || sum == ans) continue;
		if(a[i].s > st){
			sum++;
			st = a[i].e;
		}
	}
	return sum;
}//按活动安排问题的求解方式,如果美味度不符合就跳过,这里千万不要写错
int main(){
	scanf( "%d", &t);
	while (t--){
		cnt = 0;
		scanf( "%d",&n);
		for (int i = 1; i <= n; ++i){
			scanf( "%d%d%d", &a[i].s, &a[i].e, &a[i].t);
			tmp[++cnt] = a[i].t;//记录一下每个美味值,以便二分答案
		}
		sort(a + 1, a + n + 1, cmp1);//按结束时间排序
		sort(tmp + 1, tmp + cnt + 1);
		int st = a[1].e;
		ans = 1;  
		for (int i = 2; i <= n; ++i)
			if(a[i].s > st) st=a[i].e,ans++;//活动安排问题的求解方式
		printf( "%d ", ans);
		if (ans == 1){
			printf( "%d\n", tmp[cnt]);
			continue;
		}
		int l = 1, r = cnt;
		while (l <= r){
			int mid = l + r >> 1,pos = check(tmp[mid]);
			if (pos >= ans) l = mid + 1;
			else if (pos < ans) r = mid - 1;
		}
		printf( "%d\n", tmp[r]);
	}
}
©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页