51nod贪心算法教程

51nod确实是一个好oj,题目质量不错,wa了还放数据,学习算法来说挺好的,这次我做了几个水的贪心,虽然水,但是确实都很典型。

教程链接:http://www.51nod.com/tutorial/list.html

完美字符串

约翰认为字符串的完美度等于它里面所有字母的完美度之和。每个字母的完美度可以由你来分配,不同字母的完美度不同,分别对应一个1-26之间的整数。
   约翰不在乎字母大小写。(也就是说字母F和f)的完美度相同。给定一个字符串,输出它的最大可能的完美度。例如:dad,你可以将26分配给d,25分配给a,这样整个字符串完美度为77。
   分析: 由排序不等式,出现次数最多的字母显然应该给26。所以这个题目变成了统计每种字母出现的次数了,然后按照出现次数从大到小,依次分配从高到低的权值。这就是最朴素的贪心思想。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<string>
 6 #include<algorithm>
 7 #include<cctype>
 8 #include<cstdlib>
 9 using namespace std;
10 const int maxn=27;
11 int a[maxn];
12 string s;
13 bool cmp(const int a,const int b)
14 {
15     return a>b;
16 }
17 int main()
18 {
19     while(cin>>s)
20     {
21         memset(a,0,sizeof(a));
22         for(int i=0;i<s.length();i++)
23             a[tolower(s[i])-‘a‘]++;
24         sort(a,a+26,cmp);
25         long long sum=0;
26         int b=26;
27         for(int i=0;i<26;i++)
28         {
29             sum+=a[i]*b;
30             --b;
31         }
32         cout<<sum<<endl;
33     }
34     return 0;
35 }

活动安排问题

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

分析:看似最不对的策略——结束时间越早的活动优先,才是正确的贪心。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<string>
 5 #include<cmath>
 6 #include<algorithm>
 7 using namespace std;
 8 const int maxn=10000+1;
 9 typedef struct
10 {
11     int start;
12     int over;
13 }point;
14  point p[maxn];
15 const int cmp(const  point a, const  point b)
16 {
17     return a.over<=b.over;
18 }
19 int main()
20 {
21     int n;
22     while(cin>>n)
23     {
24         memset(p,0,sizeof(p));
25         for(int i=0;i<n;i++)
26             cin>>p[i].start>>p[i].over;
27         sort(p,p+n,cmp);
28         int cnt=1;
29         for(int i=0;i<n;i++)
30         {
31             for(int j=i+1;j<n;j++)
32             {
33                 if(p[i].over<=p[j].start)
34                 {
35                     i=j;
36                     cnt++;
37                     continue;
38                 }
39             }
40         }
41         cout<<cnt<<endl;
42     }
43     return 0;
44 }

活动安排问题二

有若干个活动,第i个开始时间和结束时间是[Si,fi),活动之间不能交叠,要把活动都安排完,至少需要几个教室?

上一题的升级版

分析:如果只需要教室的个数,我们可以把所有开始时间和结束时间排序,遇到开始时间就把厚度加1,遇到结束时间就把厚度减1,显然最初始和最后结束时的厚度是0,在一系列厚度变化的过程中,峰值(最大值)就是最多同时进行的活动数,也是我们至少需要的教室数。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<string>
 5 #include<cmath>
 6 #include<vector>
 7 #include<algorithm>
 8 using namespace std;
 9 const int maxn=10000+1;
10 int te[maxn],ts[maxn];
11 int main()
12 {
13     int n;
14     while(cin>>n)
15     {
16         for(int i=0;i<n;i++)
17             scanf("%d%d",&ts[i],&te[i]);
18             sort(ts,ts+n);
19             sort(te,te+n);
20             int cnt=0;
21             int mx=0,j=0;
22             for(int i=0;i<n;i++)
23             {
24                 if(ts[i]<te[j])
25                 {
26                     cnt++;
27                     if(cnt>mx)
28                         mx=cnt;
29                 }
30                 else if(ts[i]>te[j])
31                 {
32                     //cnt--;
33                     j++;
34                 }
35                 else
36                 {
37                     j++;
38                 }
39             }
40             cout<<mx<<endl;
41     }
42     return 0;
43 }

独木舟问题

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

分析:按照人的体重排序,最轻的人跟最重的人尽量安排在一条船上,如果超过就安排最重的

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<string>
 5 #include<cmath>
 6 #include<string>
 7 #include<cctype>
 8 #include<algorithm>
 9 #include<vector>
10 using namespace std;
11 const int maxn=10001;
12 int a[maxn];
13 bool cmp(long long a,long long b)
14 {
15     return a>b;
16 }
17 int main()
18 {
19     int n;
20     long long m;
21     while(cin>>n)
22     {
23         scanf("%lld",&m);
24         long long x;
25         for(int i=0;i<n;i++)
26         scanf("%lld",&a[i]);
27         sort(a,a+n,cmp);
28         long long cnt=0;
29         int i=0;
30         while(i<n)
31         {
32             if(a[n-1]+a[i]<=m)
33             {
34                 cnt++;
35                 n--;
36                 i++;
37             }
38             else
39             {
40                 i++;
41                 cnt++;
42             }
43             //cout<<a[i]<<"jk"<<a[n-1-i]<<endl;
44         }
45         //cout<<i<<"io"<<endl;
46         cout<<cnt<<endl;
47     }
48     return 0;
49 }

任务执行顺序

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

分析:

可以抽象成,从一个整数开始,每次减去a,再加上b (a,b都是正数),要求每次操作都不产生负数。
      令a[i] = R[i], b[i] = R[i] – O[i],O[i] < R[i],有0<b[i]<a[i]。 所以尽管每次有减有加,但是加的没有减的多,总数在不断减小。所以——按照b[i]不增的顺序排序,是最“有利”的。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cctype>
 5 #include<vector>
 6 #include<string>
 7 #include<cmath>
 8 #include<algorithm>
 9 using namespace std;
10 const int maxn=100001;
11 long long r[maxn],o[maxn],b[maxn],a[maxn];
12 bool cmp(long long a,long long b)
13 {
14     return a>b;
15 }
16 int main()
17 {
18     int n;
19     while(cin>>n)
20     {
21         for(int i=0;i<n;i++)
22             scanf("%lld%lld",&r[i],&o[i]);
23             for(int i=0;i<n;i++)
24             {
25                 a[i]=r[i];
26                 b[i]=r[i]-o[i];
27             }
28             sort(b,b+n,cmp);
29             long long mx=0x3fff;
30             long long ans=0;
31             for(int i=0;i<n;i++)
32             {
33                 ans-=a[i];
34                 if(ans<mx)
35                   mx=ans;
36                   ans+=b[i];
37             }
38             cout<<(0-mx)<<endl;
39     }
40     return 0;
41 }

时间: 2024-08-09 10:35:37

51nod贪心算法教程的相关文章

51nod贪心算法入门-----活动安排问题2

题目大意就是给几个活动,问要几个教室能够弄完. 这个题目的想法就是把活动的开始——结束的时间看做是数轴上的一段线段,教室的个数就是在某点的时间厚度,求最大的时间厚度就是所需要的教室个数. 1 #include<stdio.h> 2 #include<iostream> 3 #include<stdlib.h> 4 #include<queue> 5 using namespace std; 6 struct node 7 { 8 int start; 9 i

51nod贪心算法入门-----完美字符串

约翰认为字符串的完美度等于它里面所有字母的完美度之和.每个字母的完美度可以由你来分配,不同字母的完美度不同,分别对应一个1-26之间的整数. 约翰不在乎字母大小写.(也就是说字母F和f)的完美度相同.给定一个字符串,输出它的最大可能的完美度.例如:dad,你可以将26分配给d,25分配给a,这样整个字符串完美度为77. //这题水题,只要把每个字母出现的次数统计出来然后再排序一下就OK了. #include<stdio.h>#include<iostream>#include<

51nod贪心算法入门-----活动安排问题

有若干个活动,第i个开始时间和结束时间是[Si,fi),只有一个教室,活动之间不能交叠,求最多安排多少个活动? 输入 第1行:1个数N,线段的数量(2 <= N <= 10000) 第2 - N + 1行:每行2个数,线段的起点和终点(-10^9 <= S,E <= 10^9) 输出 输出最多可以选择的线段数量. 输入示例 3 1 5 2 3 3 6 输出示例 2 我们可以知道先安排最早结束的活动可以更多的安排活动.首先就是将所有的活动结束时间按先后顺序给排序:然后以结束时间为线索

算法导论笔记——第十六章 贪心算法

通常用于最优化问题,我们做出一组选择来达到最优解.每步都追求局部最优.对很多问题都能求得最优解,而且速度比动态规划方法快得多. 16.1 活动选择问题 按结束时间排序,然后选择兼容活动. 定理16.1 考虑任意非空子问题Sk,令am是Sk中结束时间最早的活动,则am在Sk的某个最大兼容活动子集中. 16.2 贪心算法原理 设计贪心算法步骤: 1>将最优化问题转化为这样的形式:对其做出一次选择后,只剩下一个子问题需要求解. 2>证明作出贪心选择后,原问题总是存在最优解,即贪心选择总是安全的. 3

POJ1017 Packets(贪心算法训练)

Time Limit: 1000MS          Memory Limit: 10000K          Total Submissions: 51306          Accepted: 17391 Description A factory produces products packed in square packets of the same height h and of the sizes 1*1, 2*2, 3*3, 4*4, 5*5, 6*6. These pro

贪心算法的简述与示例

贪心算法采用自顶向下,以迭代的方法做出相继的贪心选择,每做一次贪心选择就将所求问题简化为一个规模更小的子问题,通过每一步贪心选择,可得到问题的一个最优解,虽然每一步上都要保证能获得局部最优解,但由此产生的全局解有时不一定是最优的,所以贪婪法不要回溯.能够用贪心算法求解的问题一般具有两个重要特性:贪心选择性质和最优子结构性质. 参考:http://babybandf.blog.163.com/blog/static/61993532010112923767/ [例1]删数问题[B][/B] 试题描

算法导论——lec 13 贪心算法与图上算法

之前我们介绍了用动态规划的方法来解决一些最优化的问题.但对于有些最优化问题来说,用动态规划就是"高射炮打蚊子",采用一些更加简单有效的方法就可以解决.贪心算法就是其中之一.贪心算法是使所做的选择看起来是当前最佳的,期望通过所做的局部最优选择来产生一个全局最优解. 一. 活动选择问题 [问题]对几个互相竞争的活动进行调度:活动集合S = {a1, a2, ..., an},它们都要求以独占的方式使用某一公共资源(如教室),每个活动ai有一个开始时间si和结束时间fi ,且0 ≤ si &

五大常用算法之三贪心算法

贪心算法 贪心算法简介: 贪心算法是指:在每一步求解的步骤中,它要求"贪婪"的选择最佳操作,并希望通过一系列的最优选择,能够产生一个问题的(全局的)最优解. 贪心算法每一步必须满足一下条件: 1.可行的:即它必须满足问题的约束. 2.局部最优:他是当前步骤中所有可行选择中最佳的局部选择. 3.不可取消:即选择一旦做出,在算法的后面步骤就不可改变了. 贪心算法案例: 1.活动选择问题  这是<算法导论>上的例子,也是一个非常经典的问题.有n个需要在同一天使用同一个教室的活动a

零基础学贪心算法

本文在写作过程中参考了大量资料,不能一一列举,还请见谅.贪心算法的定义:贪心算法是指在对问题求解时,总是做出在当前看来是最好的选择.也就是说,不从整体最优上加以考虑,只做出在某种意义上的局部最优解.贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关.解题的一般步骤是:1.建立数学模型来描述问题:2.把求解的问题分成若干个子问题:3.对每一子问题求解,得到子问题的局部最优解:4.把子问题的局部最优