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;
}