0
点赞
收藏
分享

微信扫一扫

更细致的分类下,三类常见の贪心题

洛茄 2022-03-12 阅读 25

文章目录

更细致的分类下,三类常见の贪心题

最高性价比

相关知识

​​​  我们将性价比定义为单位投入量的获得量/单位获得量的投入量。也就是说,高性价比意味着

​​  ①同等投入量的高获得量 / ②同等获得量的低投入量

​​  一般这类题目会给我们很多种选择,我们根据性价比将选择进行优先级高低排序,先选择高性价比的,再选择次性价比的,直到最低性价比的,这是我认为最简单的一类贪心,往往只涉及一个排序。

相关题目

老鼠和猫的交易——同等投入量的高获得量

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mjqVVbIg-1646916048461)(C:\Users\49593\AppData\Roaming\Typora\typora-user-images\image-20220228214705114.png)]

参考思路

​​  本质上就是问,小老鼠怎么利用同等投入量的(猫粮)获得最高获得量(五香豆),那么就需要引入一个性价比的概念,很显然,此题中的性价比可以只用用单位猫粮可获得的五香豆来定义。那么大体思路就出来了,根据每一个房间的性价比,进行性价比从高到低的排序,然后依据高性价比优先策略进行交换。

参考AC代码
#include<bits/stdc++.h>
using namespace std;
struct gat{
	float amount,price,economy;
}gate[1005];
bool cmp(gat a,gat b){
	return a.economy>b.economy;
} // 定义sort函数的性价比降序排列条件 
int main(){
	int num; 
	double money,gate_num,max_sum; // define money and gate number
	ios::sync_with_stdio(false);
	while(cin>>money>>gate_num){ // enter money and gate number
		if(money==-1&&gate_num==-1)break;
		for(int i=1;i<=gate_num;i++){ // iterate all the gates
			cin>>gate[i].amount>>gate[i].price; // input the ith gate food amount and price
			gate[i].economy=gate[i].amount/gate[i].price; // calculate the ith food economy
		}
		num=(int)gate_num; // 将门的个数的浮点数强制转换为整数形式保存在num里 
		sort(gate+1,gate+num+1,cmp); // sort函数依据gate进行性价比降序
		max_sum=0; // 初始化最大购买量 
		for(int i=1;i<=gate_num;i++){ // 根据高性价比优先策略进行购买顺序的调整,即先买性价比高的,再买性价比低的 
			if(money-gate[i].price>=0){ //如果钱够,就全买;
				max_sum+=gate[i].amount; //更新购买量 
				money-=gate[i].price; //更新所剩钱数 
			}
			else{ //如果钱不够,就能买多少买多少
				max_sum+=gate[i].amount*(money/gate[i].price); //更新购买量 
				money=0; //更新所剩钱数 
			}
		}
		printf("%.3f\n",max_sum); //保留3位小数 
	}
	return 0;
} 

田忌赛马——同等获得量的低投入量

在这里插入图片描述
(C:\Users\49593\AppData\Roaming\Typora\typora-user-images\image-20220310203338758.png)]

参考思路

​​  熟悉田忌赛马的同学都知道,国王的出马策略是先出最快的马,再除次快的马,以此类推,最后出最慢的马这样一个以马速降序的顺序来出马,但是我们的出马顺序则是可以随机拟定的。我们的目标是获取最多的胜场,那么胜场就是我们追求的获得量,而消耗的马的类型就是我们的投入量。战胜对方同一匹马,其实有很多种不同的出马策略,我们本着同等获得量时低投入量的原则,对于对方的同一匹马,我们尽可能派遣己方马速比对方马速高最少的那一匹,这样就可能保证增加同等的胜场,但是消耗最少的马力。不断地按照这个策略出马,就可以求出最大胜场。
​​  想要达到这个思路,由于对方一定按降序出马,那么我们
将己方的马也按照降序排列
,然后按照顺序,依次选出第一个可以战胜对方的马,即可实现如上所述的“马尽其用”。

参考AC代码
#include<bits/stdc++.h>
using namespace std;
int main(){
   ios::sync_with_stdio(false); 
   int x,y,w,n;
   int tian[1000],wang[1000];
   while(cin>>n){
       if(n==0)break;
       w=0,x=0,y=0;
       for(int i=0;i<n;i++){
           cin>>tian[i];
       }
       for(int i=0;i<n;i++){
           cin>>wang[i];
       }
           sort(tian,tian+n,greater<int>()),sort(wang,wang+n,greater<int>());         
       while(x<n&&y<n){
           if(tian[x]>wang[y])w++,x++,y++;
           else y++;
       }
       cout<<(2*w-n)*200<<endl;    
   }
   return 0;
}

最高重叠度

相关知识

​​  这类题目的题境,一般可以转译为,几个点在一条线上移动,移动过程中,点与点不能有交集,问我们最少移动多少时间/次。例如,在寝室楼道搬桌子,规定一段楼道只能搬运一张桌子,然后桌子分布在不同的寝室,问怎样合理分配,实现最少次数的搬运。

​​  这类题中,我们将每一个个体的移动全程看成一个线段,为了更加地直观,我们可以在不同高度层画,然后我们就可以画出非常多条线段,如下所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xHv2nStk-1646916048465)
(C:\Users\49593\AppData\Roaming\Typora\typora-user-images\image-20220301225903083.png)]
​​  最少移动多少次,本质上就是问,如果有一条竖线在向右移动,最多可以与多少条横线相交,如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I8q0BPxw-1646916048465)(C:\Users\49593\AppData\Roaming\Typora\typora-user-images\image-20220301230418958.png)]
​​  为什么可以这样理解呢?这条竖线与横线的交点数,其实反映的就是最多不能同时做的事情数目。换言之,就是最少要分别做的事情数目。

​​  怎么找最多交点数呢?显然,凭我们的直觉,当移动到如下所示的地方时,相交数最多,交点数为4:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3MKJ4vcE-1646916048466)(C:\Users\49593\AppData\Roaming\Typora\typora-user-images\image-20220301230707895.png)]

​​  但是,在编程中怎么求解呢?我们可以利用循环遍历每一个线段所占据的位置,线段占据了的位置就+1,因此,对于一个横坐标x来说,有多少线段在这个坐标上出现过,它的数字就是多少。深入理解,请看以下题目。

相关题目

搬寝室

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PFBLhohq-1646916048466)(C:\Users\49593\AppData\Roaming\Typora\typora-user-images\image-20220301231506623.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZRSF6R6X-1646916048467)(C:\Users\49593\AppData\Roaming\Typora\typora-user-images\image-20220301231515153.png)]

参考思路

​​​  首先处理编号问题第12、34、56,其实共享的是同样一个地点,所以,我们要让它们相等化,那就是将每一个端点加1再整除2即可。

​​  其次,考虑一个方向问题,如果反向搬运,其实本质上和正向是一样的,那么干脆就把所有的反向改为正向的即可。
​​  最后,如何求最高重叠度?那么就在每一个经过的位置点标记加1(因为是离散点),最多标记点的标记数,就是最高重叠度,最高重叠度再乘10,那么就是搬运任务需要的最少的时间。

参考AC代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
   int i,j,T,N,s,t;
   int r[200];
   scanf("%d",&T);
   while(T--)
   {
       scanf("%d",&N);
       for(i=0;i<200;i++)
           r[i]=0;
       for(i=0;i<N;i++)
       {
           scanf("%d%d",&s,&t);
           if(s>t){
               j=s;s=t;t=j;
           }
           for(j=(s-1)/2;j<=(t-1)/2;j++)
               r[j]++;
       }
       t=r[0];
       for(i=1;i<200;i++)
           if(t<r[i]) t=r[i];
       printf("%d\n",t*10);
       
   }
   return 0;
}

最高活动数

相关知识

​​  这类题目会告诉我们,有很多活动,每一项活动都占据一定的时间段,然后要求你求出最高可安排的活动数。
​​  这种题型的解法就是按活动的结束时间进行升序排序,选最早完成的,然后在与前者不冲突的前提下选次早完成的,直到没有满足的为止,选出来的总数,就是要求的最高活动数。(可以用反证法证明,直接当结论记即可)

相关题目

今年暑假不AC

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aqM1ztSF-1646916048467)(C:\Users\49593\Desktop\image-20220301224508748.png)]

参考思路

​​​  由于有多个节目,因此我们开一个节目的数组,由于每个节目有开始时间和结束时间两个属性,因此我们利用结构体存储节目信息,因此我们用结构体数组存储这些节目的信息。按照结束时间进行升序排序,选最早完成的,然后在与前者不冲突的前提选次早完成的,知道没有满足的位置,选出来的总数,就是要求的最高活动数。
​​​  需要留心的是,由于是多组测试数据,所以在每一轮汇总,都一定要进行数据初始化。

参考AC代码
#include<bits/stdc++.h>
using namespace std;
struct jiemu{ //定义结构体来存储节目的起始时间两个数据
   int a;
   int b;
};
bool cmp(jiemu x, jiemu y){ //排序时先按结束时间从小到大排序,如结束时间相同,按开始时间从大道小排序
   if(x.b==y.b) return x.a>y.a;
   return x.b<y.b;
}
int main()
{
   int x,y,s,N;
   jiemu jm[100];
   ios::sync_with_stdio(false);
   while(cin>>N){
       if(N==0) break;
       x=0,y=1,s=1; //循环的话,每次的初始化很重要,初始化的内容,就是与结果相关的一切内容
       for(int i=0;i<N;i++){
           cin>>jm[i].a>>jm[i].b;
       }
       sort(jm,jm+N,cmp);
       while(x<N&&y<N){ //这里的逻辑一定是要与,不然会出错
           if(jm[x].b<=jm[y].a) s++,x=y,y++; //找到合适的,长度加一,更新被最新的节目x为刚才的y,再将y右移
           else y++;  //没找到,y还是右移
       }
       cout<<s<<endl;
   }
   return 0;
}
举报

相关推荐

0 条评论