贪心入门讲解

QAQ先抛出一个简单的例子热身一下~:

 

约翰认为字符串的完美度等于它里面所有字母的完美度之和。每个字母的完美度可以由你来分配,不同字母的完美度不同,分别对应一个1-26之间的整数。

约翰不在乎字母大小写。(也就是说字母F和f)的完美度相同。给定一个字符串,输出它的最大可能的完美度。例如:dad,你可以将26分配给d,25分配给a,这样整个字符串完美度为77。

输入

 

输入一个字符串S(S的长度 <= 10000),S中没有除字母外的其他字符。

 

输出

 

由你将1-26分配给不同的字母,使得字符串S的完美度最大,输出这个完美度。

 

输入示例

 

dad


输出示例

 

77

 

 

 

分析可知,只要让出现最多的字母的权值最大即可,所以首先要统计每个字母出现的次数,从大到小排序,从大到小依次赋值,

AC代码如下:

 

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int main(){
	char str[10005];
	int cnt[30];
	while(~scanf("%s",str)){
		memset(cnt,0,sizeof(cnt));
		for(int i = 0; i < strlen(str); i ++){
			if(str[i] >= 'A' && str[i] <= 'Z')
				cnt[str[i] - 'A'] ++;
			else
				cnt[str[i] - 'a'] ++;
		}
		sort(cnt,cnt+26);
		long long sum = 0;
		int j = 26;
		for(int i = 25; i >= 0 && cnt[i]; i --){
			sum += cnt[i] * j;
			j --;
		}
		printf("%lld\n",sum);
	}
	return 0;
}

 

 

 

 

 

是不是不过瘾QAQ,(再来一个有趣的题目:

X轴上有N条线段,每条线段有1个起点S和终点E。最多能够选出多少条互不重叠的线段。(注:起点或终点重叠,不算重叠)。

例如:[1 5][2 3][3 6],可以选[2 3][3 6],这2条线段互不重叠。

输入

 

第1行:1个数N,线段的数量(2 <= N <= 10000)
第2 - N + 1行:每行2个数,线段的起点和终点(-10^9 <= S,E <= 10^9)

 

输出

 

输出最多可以选择的线段数量。

 

输入示例

 

3
1 5
2 3
3 6


输出示例

 

2

 

 

 

 

问题让求的是最多能够有多少不重合的线段,可以这样分析,当前存在两条线段,如果一条线段的结束时间小于另一条线段的开始时间,则两条线段即不重合。所以可以得出,只要按照线段的结束点从小到大排序,把前一条线段的结束点同后一条线段的开始点相比较即可。

AC代码如下:

 

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

struct node{
	int x,y;
}p[10005];
int n;

bool cmp(node A, node B){
	return A.y < B.y;
}

int main(){
	while(~scanf("%d",&n)){
		for(int i = 0; i < n; i ++){
			scanf("%d%d",&p[i].x,&p[i].y);
		}
		sort(p,p+n,cmp);
		int cnt = 1,j=0;//用j来记录要结束的时间点 
		for(int i = 1 ; i < n; i ++){
			if(p[i].x >= p[j].y){//当前线段的起点大于前一线段的结束点 
				j = i;
				cnt ++;
			}
		}
		printf("%d\n",cnt);
	}
	return 0;
}

 

 

 

 

 

再来一道和上面同宗的题目^_^:

有若干个活动,第i个开始时间和结束时间是[Si,fi),同一个教室安排的活动之间不能交叠,求要安排所有活动,最少需要几个教室? 

 

输入

 

第一行一个正整数n (n <= 10000)代表活动的个数。
第二行到第(n + 1)行包含n个开始时间和结束时间。
开始时间严格小于结束时间,并且时间都是非负整数,小于1000000000

 

输出

 

一行包含一个整数表示最少教室的个数。

 

输入示例

 

3
1 2
3 4
2 9


输出示例

 

2

 

 

 

这道题目让求得是用的最少的教室,实际上就是求最少数量的重叠线段数,如果两条线段重叠,则说明一条线段的终点大于另一条线段的起点,所以判断当前的两条线断是否重叠,只要判断起点和终点之间的关系即可,所以只需要把起点和终点(分存在两个数组)按照从小到大排序,如果起点小于终点,则cnt++,否则j++(j表示起点的下标)。

贴一下51nod上的讲解:

 

策略: 按照开始时间排序优先安排活动,如果冲突,则加一个教室。
简单地理解一下,策略是这样,我们把活动按照开始时间有小到大的顺序排序。假设目前已经分配了k个教室(显然k初始等于0),对于当前这个活动,
(1) 如果它能安排在k个教室里的某一个,则把它安排在其中的任何一个教室里,k不变。
(2) 否则它和每个教室里的活动都冲突,则增加一个教室,安排这个活动。


这个策略是最优么?


我们想像一下k增加1的过程: 因为我们是按照开始时间排序的,意味着当前考虑的这个活动开始的时候,k个教室里都有活动没结束(因为如果有一个教室的活动结束了,我们就可以安排这个活动进入那个教室而不冲突,从而不用增加k)。这就意味着在这个活动开始的时间点,算上目前考虑的这个活动,有(k + 1)个活动正在进行,同一时刻有(k + 1)个活动在进行,无论我们如何安排教室,都至少需要(k + 1)个教室。因为每个教室里不能同时进行两个活动。而我们的策略恰好需要(k + 1)个教室,所以是最优的。

 

 

 

 

下面给出AC代码:

 

 

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int start[10005],end[10005],n;

int main(){
	while(~scanf("%d",&n)){
		for(int i = 0; i < n; i ++){
			scanf("%d%d",&start[i],&end[i]);
		}
		sort(start,start+n);
		sort(end,end+n);
		
		long long j=0,cnt=0,sum=0;
		for(int i = 0; i < n; i ++){
			if(start[i] < end[j]){//起点小于终点,则说明存在不结束的 
				cnt ++;
				if(cnt > sum)
					sum = cnt;
			}
			else
				j ++;
		}
		printf("%lld\n",sum);
	}
	return 0;
}

 

 

 

 

 

 

是不是不过瘾,还有题目等你O(∩_∩)O哈哈~:

n个人,已知每个人体重。独木舟承重固定,每只独木舟最多坐两个人,可以坐一个人或者两个人。显然要求总重量不超过独木舟承重,假设每个人体重也不超过独木舟承重,问最少需要几只独木舟?

 

输入

 

第一行包含两个正整数n (0<n<=10000)和m (0<m<=2000000000),表示人数和独木舟的承重。
接下来n行,每行一个正整数,表示每个人的体重。体重不超过1000000000,并且每个人的体重不超过m。

 

输出

 

一行一个整数表示最少需要的独木舟数。

 

输入示例

 

3 6
1
2
3


输出示例

 

2

 

 

 

 

一个独木舟最多只能够坐两人,并且重量不能够超过m,可以这样分析,每次只需让没有上舟的人中的重量最大和最小的两人与限定的重量m作比较即可,大于则只让重量最大的上舟,否则两人都上舟。

AC代码如下:

 

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int a[10005],n,m;

int main(){
	while(~scanf("%d%d",&n,&m)){
		for(int i = 0; i < n; i ++){
			scanf("%d",&a[i]);	
		}
		sort(a,a+n);
		int i = 0,j=n-1;
		long long cnt = 0;
		while(i <= j){
			if(a[i] + a[j] <= m){//符合上船条件 
				i ++; j --;
			}
			else{//不符合则只让重的上船 
				j --;
			}
			cnt ++;
		}
		printf("%lld\n",cnt);
	}
	return 0;
}

 

 

 

 

 

O(∩_∩)O哈哈~千呼万唤始出来,终于到了最后一个例子:

有N个任务需要执行,第i个任务计算时占R[i]个空间,而后会释放一部分,最后储存计算结果需要占据O[i]个空间(O[i] < R[i])。

例如:执行需要5个空间,最后储存需要2个空间。给出N个任务执行和存储所需的空间,问执行所有任务最少需要多少空间。

输入

 

第1行:1个数N,表示任务的数量。(2 <= N <= 100000)
第2 - N + 1行:每行2个数R[i]和O[i],分别为执行所需的空间和存储所需的空间。(1 <= O[i] < R[i] <= 10000)

 

输出

 

输出执行所有任务所需要的最少空间。

 

输入示例

 

20
14 1
2 1
11 3
20 4
7 5
6 5
20 7
19 8
9 4
20 10
18 11
12 6
13 12
14 9
15 2
16 15
17 15
19 13
20 2
20 1


输出示例

 

135

 

 

 

实际这道题目也不难,毕竟这只是贪心入门的讲解嘛,只需要让一个任务执行完后剩下的空间最大即可,所以只需按照R[i]-O[i]从大到小排序即可。

AC代码如下:

 

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int n;
struct node{
	int R,O;
}p[100005];

bool cmp(node A, node B){
	return A.R-A.O > B.R-B.O;
}

int main(){
	while(~scanf("%d",&n)){
		for(int i = 0; i < n; i ++){
			scanf("%d%d",&p[i].R,&p[i].O);
		}
		sort(p,p+n,cmp);
		
		long long sum=0,space=0;
		for(int i = 0; i < n; i ++){
			if(p[i].R > space){//当前存储空间不够 
				sum += p[i].R - space; //增加的存储空间 
				space = p[i].R - p[i].O; //还剩下的存储空间 
			}
			else//当前存储空间足够 
				space -= p[i].O;//还剩下的存储空间 
		}
		printf("%lld\n",sum);
	}
	return 0;
}

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值