贪心算法(基础)

       贪心算法的主要特点是一个大的问题可以分成几个小的子问题,我们在进行选择时永远选择在目前看来最优的选项而不管我们当前的选择对之后选择的影响,即子问题的结果对后来的结果没有干扰,我们寻找子问题的最优解的同时,最终将所有子问题的最优解的合近似处理成大问题的解,在一些情况下这是行的通的,贪心的题目都具有明显的特点。接下来几个题目就是典型的贪心算法。

一.部分背包问题

题目来自洛谷

题目描述

阿里巴巴走进了装满宝藏的藏宝洞。藏宝洞里面有 N(N≤100) 堆金币,第 i堆金币的总重量和总价值分别是mi​,vi​(1≤mi​,vi​≤100)。阿里巴巴有一个承重量为 T(T≤1000) 的背包,但并不一定有办法将全部的金币都装进去。他想装走尽可能多价值的金币。所有金币都可以随意分割,分割完的金币重量价值比(也就是单位价格)不变。请问阿里巴巴最多可以拿走多少价值的金币?

输入格式

第一行两个整数 N,T。

接下来 N行,每行两个整数mi​,vi​。

输出格式

一个实数表示答案,输出两位小数

题解

         因为要装走尽可能多价值的金币,在背包容量有限的情况下,我们的目的就是使背包内的单位空间的金币价值最大,就是要装价值/重量最大的金币,因为金币可以随意分割,所以将金币按价值重量币排序后依次装满背包即可.这里使用结构体来储存金币的重量,价值,价值/重量的信息.将结构体数组排序后遍历即可.

AC代码

/*@_krito*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
struct coin{
	float w;
	float v;
	float b;
};
bool cmp(coin a,coin b){
	return a.b>b.b;
}
int main(){
	int n,t;
	float ans=0;
	coin c[101];
	cin>>n>>t;
	for(int i=1;i<=n;i++){
		cin>>c[i].w;
		cin>>c[i].v;
		c[i].b=c[i].v/c[i].w;
	}
	sort(c+1,c+n+1,cmp);
	for(int i=1;i<=n&&t!=0;i++){
		if(t>=c[i].w){
			ans+=c[i].v;
			t-=c[i].w;
		}
		else {
			ans+=c[i].b*t;
			t=0;
		}
	}
	printf("%.2f",ans);
} 

二.排队接水问题.

题目描述

有 n 个人在一个水龙头前排队接水,假如每个人接水的时间为 Ti​,请编程找出这 n 个人排队的一种顺序,使得 n 个人的平均等待时间最小。

输入格式

第一行为一个整数 n。

第二行 n 个整数,第 i 个整数 Ti​ 表示第 i 个人的等待时间 Ti​。

输出格式

输出文件有两行,第一行为一种平均时间最短的排队顺序;第二行为这种排列方案下的平均等待时间(输出结果精确到小数点后两位)。

题解 

        几乎是与上题思路相同,先让接水时间短的人在前,然后求解即可.

AC代码

/*@_krito*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 1001
int main(){
	int n,a[N],b[N];
	bool vis[N]={false};
	cin>>n;
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		b[i]=a[i];
	}
	sort(a+1,a+n+1);
	double sum=0,rec=0;
	for(int i=1;i<=n-1;i++){
		for(int j=1;j<=n;j++)
		if(a[i]==b[j]&&!vis[j]){
			printf("%d ",j);
			vis[j]=true;
			break;
			}
		rec+=a[i];
		sum+=rec;
	}
	for(int i=1;i<=n;i++){
		if(!vis[i]) cout<<i;
	}
	sum=sum/(double)n;
	printf("\n%.2lf",sum);
}

接下来的题目思路大致一样,就不再详细说明,可以感受的到贪心算法的题目特征还是非常明显的,有一些看似是贪心但是最后出错的题应该就是dp了,贪心是dp的一种特殊情况.

三.合并果子

题目描述

在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。

每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过 n−1 次合并之后, 就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。

因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为 11 ,并且已知果子的种类 数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。

例如有 33 种果子,数目依次为 1 , 2 , 9 。可以先将 1 、 2 堆合并,新堆数目为 3 ,耗费体力为 3 。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为 12 ,耗费体力为 12 。所以多多总共耗费体力 =3+12=15 。可以证明 15 为最小的体力耗费值。

输入格式

共两行。
第一行是一个整数 n(1≤n≤10000) ,表示果子的种类数。

第二行包含 n个整数,用空格分隔,第 i 个整数 ai​(1≤ai​≤20000) 是第 ii 种果子的数目。

输出格式

一个整数,也就是最小的体力耗费值。输入数据保证这个值小于 2^{31} 。

AC代码(上次的代码贴错了)

/*@_krito*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 10001
int main(){
	priority_queue<int,vector<int>,greater<int> >q;
	int n,ans;
	cin>>n;
	for(int i=1;i<=n;i++){
		int x;
		cin>>x;
		q.push(x);
	}
	while(q.size()>=2){
		int a=q.top();
		q.pop();
		int b=q.top();
		q.pop();
		ans+=a+b;
		q.push(a+b);
	}
	cout<<ans;
}

四.A. Divan and a Store(题目来自codeforces)

A. Divan and a Store

time limit per test

1 second

memory limit per test

256 megabytes

input

standard input

output

standard output

Businessman Divan loves chocolate! Today he came to a store to buy some chocolate. Like all businessmen, Divan knows the value of money, so he will not buy too expensive chocolate. At the same time, too cheap chocolate tastes bad, so he will not buy it as well.

The store he came to has nn different chocolate bars, and the price of the ii-th chocolate bar is aiai dollars. Divan considers a chocolate bar too expensive if it costs strictly more than rr dollars. Similarly, he considers a bar of chocolate to be too cheap if it costs strictly less than ll dollars. Divan will not buy too cheap or too expensive bars.

Divan is not going to spend all his money on chocolate bars, so he will spend at most kk dollars on chocolates.

Please determine the maximum number of chocolate bars Divan can buy.

Input

Each test contains multiple test cases. The first line contains the number of test cases tt (1≤t≤1001≤t≤100). Description of the test cases follows.

The description of each test case consists of two lines. The first line contains integers nn, ll, rr, kk (1≤n≤1001≤n≤100, 1≤l≤r≤1091≤l≤r≤109, 1≤k≤1091≤k≤109) — the lowest acceptable price of a chocolate, the highest acceptable price of a chocolate and Divan's total budget, respectively.

The second line contains a sequence a1,a2,…,ana1,a2,…,an (1≤ai≤1091≤ai≤109) integers — the prices of chocolate bars in the store.

Output

For each test case print a single integer — the maximum number of chocolate bars Divan can buy.

题目链接

AC代码

/*@_krito*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 101
int main(){
	int t;
	cin>>t;
	while(t--){
		ll n,l,r,k=0,ans=0,a[N];
		cin>>n>>l>>r>>k;
		int j=1;
		for(int i=1;i<=n;i++){
			int temp;
			cin>>temp;
			if(temp>=l&&temp<=r){
				a[j]=temp;
				j++;
			}
		}
		sort(a+1,a+j);
		for(int i=1;i<j;i++){
			k-=a[i];
			if(k>=0)
			ans++;
		}
		cout<<ans<<endl;
	}
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Krito.

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值