【全网首发】洛谷贪心题解集合

贪心

1.P2240 【深基12.例1】部分背包问题

【深基12.例1】部分背包问题 - 洛谷

思路

万不要被题目给误导了,这道题是贪心。

所有金币都可以分开,也就是说只要按照性价比最高的取一定得到的价值最大。

性价比就是这堆金币的价值除以重量。

只需要把这n堆金币按性价比排序就行了。

然后依次遍历,如果背包中剩余可以拿的重量大于等于这堆金币的重量,就全拿,否则直接装满。

直接装满这里注意一下整型转浮点的细节就好了。

AC

#include<bits/stdc++.h>
using namespace std;
double ans,t;
struct gold{
	double m,r;
}a[105];
bool cmp(gold u,gold v){
	return u.r>v.r;
}
int n;
int main(){
	cin>>n>>t;
	for(int i=1;i<=n;i++){
		double x,y;
		cin>>x>>y;
		a[i].m=x;
		a[i].r=y/x;
	}
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=n;i++){
		if(a[i].m<t){
			t-=a[i].m;
			ans+=a[i].r*a[i].m;
		}
		else{
			ans+=t*a[i].r;
			break;
		}
	}
	printf("%.2f",ans);
	return 0;
}

2.P1803 凌乱的yyy / 线段覆盖

凌乱的yyy / 线段覆盖 - 洛谷

思路

这道题考查的应该是贪心, 贪心的地方在于每次都选择结束时间最早的那场比赛,最后的参赛次数应该是最高的(详情请见其他dalao的题解),所以代码就十分简单了,利用sort快排把结束顺序从小到大排列,然后根据上场比赛的结束时间和本场比赛的开始时间一一检查能否参加就可以了。

AC

#include<bits/stdc++.h>
#define f first //将first用f表示
#define s second//将second用s表示
using namespace std;
typedef pair<int,int>pi;
int const m=1e6+5;
pi a[m];
int n;
int main(){
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>a[i].s>>a[i].f;
	}
	sort(a,a+n);
	int last=0,ans=0;
	for(int i=0;i<n;i++){
		if(a[i].s>=last){
			ans++;
			last=a[i].f;
		}
	}
	cout<<ans<<endl;
	return 0;
}

3.P1190 [NOIP2010 普及组] 接水问题

[NOIP2010 普及组] 接水问题 - 洛谷

思路

首先,我们理解了题目,哪个人装完水之后,就轮到队伍的下一个人来接水.So,下一个来接水的人,一定是去当前装水的m个人中最快的那个人的位置继续装水.

Then,我们就可以从第m+1个人开始帮他找位置(PS:为什么不是从第一个人开始?因为前m个人已经在装水了,他们的位置随便定(写程序的时候不用管)).因为要去速度最快的那个人的位置,所以,到那个位置装水的人的时间之和也是最短的!

那么,我们就可以利用数组中前m个位置来储存相对应位置接水的人时间之和.这样的话,每次就可以先找m个接水位置中,当前时间之和最短的来装水(即把a[i]加到a[1](当前总用时最短的位置)),就OK啦!

最后,再看一下前m个位置中那个用的时间是最短的,cout就可以完成啦!

AC

#include<bits/stdc++.h>
using namespace std;
int s[11000],ans; 
int main(){
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>s[i];
	}
	int t=m+1;
	while(t<=n+m){
		for(int i=1;i<=m;i++){
			s[i]--;
			if(s[i]==0){
				s[i]=s[t];
				t++;
			}
		}
		ans++;
	}
	cout<<ans;
	return 0;
}

4.P1080 [NOIP2012 提高组] 国王游戏

[NOIP2012 提高组] 国王游戏 - 洛谷

思路

看到这道题的使得获得奖赏最多的大臣,所获奖赏尽可能的少,我的第一想法是二分答案。但是又仔细想了想,答案不具有单调性,二分是行不通的。

再看看这道题,我感觉可以用贪心来做。也就是说先用贪心确定一种最优的方案,再在这个排列队伍中求得答案。

可以这样思考,相邻两个的人交换对于前面的人答案没影响(这不是废话么),而且对于后面的人答案也没有影响(这里很关键)。也就是说相邻两人的位置交换只会对这两个人产生影响。那么我们就先考虑这两个人。

设这两个人分别为i和i+1。左手数字为a[i]和a[i+1],右手数字为b[i]和b[i+1]。两人的金币数为w[i]和w[i+1]。

记P[i]=a[1]*a[2]a[3]...*a[i]

可得:

w[i]=P[i-1]/b[i];

w[i+1]=P[i]/b[i+1];

又P[i]=P[i-1]*a[i]

那么 w[i+1]=P[i-1]*a[i]/b[i+1]=w[i]*a[i]*b[i]/b[i+1]

不难看出,在这个相邻的二元组中,前面的数不受后面的影响,而后面的金币数决定于w[i],a[i],b[i]。

推广到整个排队方案,前面的金币数和a[i],b[i]都会影响后面的答案。贪心原则便出来了:按a[i]*b[i]为关键字从小到大排序,相同的顺序无所谓。最后再扫一遍,算出答案即可。

此题需要注意一点:乘除法都要写高精度,且答案有10000多位。

AC

#include<bits/stdc++.h>
#define ll long long
#define ld long double
using namespace std;
string hmul(string a,string  b){
    int c[500005];
    memset(c,0,sizeof c);
    int x[a.size()],y[b.size()];
    memset(x,0,sizeof x);
    memset(y,0,sizeof y);
    for(unsigned int i=0;i<a.size();i++)
        x[a.size()-1-i]=a[i]-'0';
    for(unsigned int i=0;i<b.size();i++)
        y[b.size()-i-1]=b[i]-'0';
    for(unsigned int i=0;i<a.size();i++){
        for(unsigned j=0;j<b.size();j++){
            c[i+j]+=x[i]*y[j];
        }
    }
    for(unsigned int i=0;i<a.size()+b.size();i++){
        if(c[i]>=10){
            c[i+1]+=c[i]/10;
            c[i]%=10;
        }
    }
    string ci;
    bool p=1;
    for(int i=a.size()+b.size()-1;i>=0;i--){
        if(c[i]==0&&p) continue;
        else{
            p=0;
            ci+=c[i]+'0';
        }
    }return ci;
}
string hdiv(string a,int b){
    int x[50005];
    int y[50005];
    memset(x,0,sizeof(x));
    memset(y,0,sizeof(y));
    for(unsigned int i=0;i<a.size();i++){
        x[i+1]=a[i]-'0';
    }
    int yu=0;
    for(unsigned int i=1;i<=a.size();i++){
        y[i]=(yu*10+x[i])/b;
        yu=(yu*10+x[i])%b;
    }
    int kk=1;
    while(y[kk]==0&&kk<a.size()) kk++;
    string aa;
    for(unsigned int i=kk;i<=a.size();i++){
        aa+=y[i]+'0';
    }return aa;
}
string smx(string a,string b){
    if(a.size()!=b.size()) return a.size()>b.size()?a:b;
    return a>b?a:b;
}
string tur_str(int num){
    string str;
    while(num){
        str+=num%10+'0';
        num/=10;
    }
    reverse(str.begin(),str.end());
    return str;
}
int n;
struct aa{
    int l,r;
}a[100005];
bool cmp(aa a,aa b){
    return (a.l*a.r)<(b.l*b.r);
}
int main(){
    cin>>n;
    cin>>a[0].l>>a[0].r;
    for(int i=1;i<=n;i++) cin>>a[i].l>>a[i].r;
    sort(a+1,a+n+1,cmp);
    string ans="0";
    string xx=tur_str(a[0].l);
    for(int i=1;i<=n;i++){
        ans=smx(ans,hdiv(xx,a[i].r));
        xx=hmul(xx,tur_str(a[i].l));
    }cout<<ans<<endl;
    return 0;
}

​​​​​

### 洛谷平台上的Python题目解法及其排序 对于洛谷平台上的Python题目,可以根据不同的标准进行分类和排序。以下是几种常见的排序方法: #### 1. 按照难度级别排序 可以将题目按照其官方标注的难度等级由易到难排列。这种方式有助于初学者逐步提升编程能力。 ```python easy_problems = ["B2002", "B2025"] # 简单题目的例子[^4] medium_problems = [] # 中等难度题目列表 hard_problems = [] # 较难题目列表 all_sorted_by_difficulty = easy_problems + medium_problems + hard_problems print(all_sorted_by_difficulty) ``` #### 2. 按照标签或知识点排序 依据每道题所涉及的知识点来整理,比如字符串处理、数组操作或是算法设计等内容模块化管理。 ```python string_operations = ["P5704", "P5705"] algorithm_design = ["P1080"] sorted_by_topic = string_operations + algorithm_design for problem_id in sorted_by_topic: print(problem_id) ``` #### 3. 使用快速排序对特定数据集进行排序 当面对具体的数据集合时,可应用快速排序算法对其进行高效有序排列。 ```python def quick_sort(arr): if len(arr) <= 1: return arr else: pivot = arr[len(arr) // 2] left = [x for x in arr if x < pivot] middle = [x for x in arr if x == pivot] right = [x for x in arr if x > pivot] return quick_sort(left) + middle + quick_sort(right) problem_ids = ['P1000', 'P1001', 'P1059'] ordered_problem_ids = quick_sort(problem_ids) print(ordered_problem_ids) ``` #### 4. 特殊情况下的自定义排序逻辑 针对某些特殊需求(如国王游戏中的贪心策略),可能需要编写专门的比较函数来进行定制化的排序过程[^2]。 ```python from functools import cmp_to_key def custom_compare(x, y): # 实现具体的比较规则 pass special_cases = [...] # 待排序项 custom_ordered_items = sorted(special_cases, key=cmp_to_key(custom_compare)) print(custom_ordered_items) ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喷火龙廖

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值