贪心2——2021-01-29更

贪心2——SSL 贪心板块

T1 备战考试

题目:

马上快期末考试了,各科都安排了很多课后训练,但是这些时间有可能会有冲突。

小b为了考出好成绩,他想在时间不冲突的情况下,参加训练的越多越好。

现在小b拿到了所有训练的时间段安排,请你计算他最多能参加多少项训练。

输入
第一行是一个数 n ( 1<= n <=10^6),表示安排的训练数。
接下来 n 行, 每行两个整数 ai , bi,表示各个训练的开始和结束时间。 ( 0<=ai < bi<=10^6)

输出
一个整数,表示最多参加的训练数。

输入样例
3
0 2
2 4
1 3

输出样例
2

思路:

这道题目是一道经典的贪心题,用线段排序,以每个训练结束的时间来排,如果结束时间相同,那么就以时间长短来排,排完之后这道题目就很好做了。这道题关键在于要想到用线段排序来做。

代码:

#include<bits/stdc++.h> 
using namespace std;
int n;
struct xl
{
    
    
	int qd,zd,sj;
}a[1000010];

bool cmp(xl q,xl p)
{
    
    
	if(q.zd==p.zd)
		return q.sj<p.sj;
	return q.zd<p.zd;
}
int main()
{
    
    
	ios::sync_with_stdio(false);//输入输出优化
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
    
    
		scanf("%d%d",&a[i].qd,&a[i].zd);
		a[i].sj=a[i].zd-a[i].qd;
	}
	sort(a+1,a+1+n,cmp);
	int h=1,k=1;
	for(int i=2;i<=n;i++)
	{
    
    
		if(a[i].qd>=a[k].zd)
		{
    
    
			h++;
			k=i;
		}
	}	
	printf("%d",h);
	return 0;
} 

T2 智力问答

题目:

在某智力问答节目的规则是这样的:首先节目组会奖励参赛者 m 元,然后提供n(n<=500)道问答题,每道题必须在规定的时间ti(含ti)前完成(1<=ti<=n)。如果一道题没能在规定时间前完成,则要从m元中扣去相应的钱数wi(wi是正整数且各不相同)。
作为参赛者,当然想知道如何安排答题顺序,使得最后能得到的钱最多。
输入

第1行为m,表示一开始奖励给参赛者的钱;
第2行为n,表示问答题的数量;
第3行有n个数,分别表示1到n题的规定完成时间;
第4行有n个数,分别表示1到n题不能在规定时间前完成的扣款数。

输出
一个整数,表示参赛者最多能赢取的钱数(数据保证不会亏钱)。

输入样例
10000
7
4 2 4 3 1 4 6
70 60 50 40 30 20 10

输出样例
9950

思路:

这道题目我一开始走入了一个错误的思路,就是以扣的钱数从大到小排序,结果就做错了,我想了很久,考虑到一个问题,每道题目都有一个限定时间,那我在最后一分钟去做这道题不就行了,如果在这一分钟我已经安排了题目,那就比较钱数,钱数少的就往前排,按照这个思路,当出现一道题目没地方安排的时候,就减去相应的钱就好了。

代码:

#include<bits/stdc++.h> 
using namespace std;
int n,h,b[600],k;
struct node
{
    
    
	int kq,sj;
}a[510];

int main()
{
    
    
	ios::sync_with_stdio(false);
	scanf("%d%d",&h,&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i].sj);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i].kq);
	for(int i=1;i<=n;i++)
	{
    
    
		k=i;
		for(int j=a[i].sj;j>=1;j--)
		{
    
    
			if(b[j]==0||a[k].kq>a[b[j]].kq)
				swap(k,b[j]);
		}
		h-=a[k].kq;
	}	
	printf("%d",h);
	return 0;
} 

T3 安装饮水机

题目:

为倡导城市低碳生活,市文明办计划举办马拉松比赛,为确保比赛安全,沿途设置 了一些观察点。每个观察点派一个观察员驻守。由于天气比较炎热,需要在沿途安装一 些饮水机,使得观察员可以去取水喝。由于观察员每移动一个单位的路程,需要耗费一 个单位的体力。而每个观察员的体力有限,只能在他体力能支持的范围内去取水喝,要 不他就会渴死或累死。 聪明的楠楠也参与了这次比赛的筹备工作。
他的任务是设计一个理想的安装饮水机 方案,使得安装的饮水机最少,但又保证所有观察员都能取到水喝。

输入
第一行,仅一个整数,表示有 N(0< n <=1000)个观察点。
接下来有 N 行,每行两个整数 S(0 < S <=100000)和
W(0< W <=50000),其中 S 表示某 个观察点到起点的路程,W 表示该观察点中驻点观察员的体力。

输出
一个整数,表示最少要安装几台饮水机。

输入样例
4
6 3
12 2
1 5
14 5

输出样例
2

思路:

这道题目乍一看好像没什么思路,所以我一开始做的时候也没有头绪,用暴力解法,然后……就TLE了(后来发现是数组开小了),于是我又重新分析了题目,发现体力足以观察员到的位置,可以当做是一条线段,这条线段的头和尾就是观察员能到达的极限距离,那么,就可以用线段排序来做了,思路和T1一样,也是以终点(尾)的位置来排,然后再用for循环,如果当前观察员可到的范围已经不在预先设定好的观察员的活动范围,那么就把当前这个观察员作为设定点,再往后找,同时把饮水机台数+1.

代码:

#include<bits/stdc++.h> 
using namespace std;
int n,h=1;
bool v[1010];
struct gcd
{
    
    
	int qd,zd,wz,tl;
}a[1010];

bool cmp(gcd q,gcd p)
{
    
    
	return q.zd<p.zd;
}
int main()
{
    
    
	ios::sync_with_stdio(false);
	cin>>n;
	for(int i=1;i<=n;i++)
	{
    
    
		cin>>a[i].wz>>a[i].tl;
		a[i].qd=a[i].wz-a[i].tl;
		a[i].zd=a[i].wz+a[i].tl;
	}
	sort(a+1,a+1+n,cmp);
	int k=a[1].zd;
	for(int i=1;i<=n;i++)
	{
    
    
		if(a[i].qd>k)
		{
    
    
			h++;
			k=a[i].zd;
		}
	}
	cout<<h;
	return 0;
} 

这些就是贪心集合的所有内容了,还是那句话,贪心就是一种经验,没有规律可循,也没有模板,需要靠多练习来熟练运用。 其实不管是什么算法,都要靠多练习来熟练运用。

贪心系列——贪心1

猜你喜欢

转载自blog.csdn.net/SSL_wyd/article/details/113406600