贪心:贪婪算法是一种算法范例,它遵循在每个阶段做出局部最优选择的启发式求解方法,目的是寻找到一个全局最优解。
用处:①活动安排
设有N个活动时间集合,每个活动都要使用同一个资源,比如说会议场,而且同一时间内只能有一个活动使用,每个活动都有一个使用活动的开始si和结束时间fi,即他的使用区间为(si,fi),现在要求你分配活动占用时间表,即哪些活动占用该会议室,哪些不占用,使得他们不冲突,要求是尽可能多的使参加的活动最大化,即所占时间区间最大化!
具体思路如下:首先,我们需要将这些活动按照结束时间从小到大排序。然后每次选出一个活动,他的开始时间要大于上一个选择的活动的结束时间,同时在剩余的活动里,他的结束时间是最早的。选择的第一个活动就是结束时间最早的那个活动。
②线段覆盖
在一维空间中告诉你N条线段的起始坐标与终止坐标,要求求出这些线段一共覆盖了多大的长度。
具体思路如下:用起始点为顺序进行排列,若初始与末尾结点均大于上个结点的末尾结点,则加上这一段的长度,若初始小于末尾则补上多余的部分长度。
③数字组合问题
设有N个正整数,现在需要你设计一个程序,使他们连接在一起成为最大的数字,例3个整数 12,456,342 很明显是45634212为最大,4个整数 342,45,7,98显然为98745342最大。
具体思路如下:常规思路为字符串比较大小后排序;若要用数值比较则要比较组合后的大小且用冒泡排序;
④···
例题1:
题目描述
小伟报名参加中央电视台的智力大冲浪节目。本次挑战赛吸引了众多参赛者,主持人为了表彰大家的勇气,先奖励每个参赛者 元。接下来主持人宣布了比赛规则:
首先,比赛时间分为 个时段 ,它又给出了很多小游戏,每个小游戏都必须在规定期限 前完成 。如果一个游戏没能在规定期限前完成,则要从奖励费 元中扣去一部分钱 , 为自然数,不同的游戏扣去的钱是不一样的。当然,每个游戏本身都很简单,保证每个参赛者都能在一个时段内完成,而且都必须从整时段开始。主持人只是想考考每个参赛者如何安排组织自己做游戏的顺序。作为参赛者,小伟很想赢得冠军,当然更想赢取最多的钱!注意:比赛绝对不会让参赛者赔钱!
输入
第一行为 ,表示一开始奖励给每位参赛者的钱;
第二行为 ,表示有 个小游戏;
第三行有 个数,分别表示游戏 到 的规定完成期限;
第四行有 个数,分别表示游戏 到 不能在规定期限前完成的扣款数。
输出
输出小伟能赢取最多的钱。
样例输入
10000
7
4 2 4 3 1 4 6
70 60 50 40 30 20 10
样例输出
9950
优先保证完成奖励多的任务,每个任务的时间互相不冲突,如果完成不了就把响应的钱数扣掉,
#include <iostream> #include <algorithm> using namespace std; //每个任务的时间和金钱 struct task { int t, m; }; bool cmp(task a, task b) { if (a.m == b.m) return a.t < b.t; return a.m > b.m; } //标记数组标记时间 int n, m, mark[100000] = {1}; task game[505]; int main() { cin >> m >> n; for (int i = 0; i < n; i++) { cin >> game[i].t; } for (int i = 0; i < n; i++) { cin >> game[i].m; } sort(game, game + n, cmp); for (int i = 0; i < n; i++) { for (int j = game[i].t; j >= 0; j--) { //如果时间没有被用过,则标记1 if (mark[j] == 0) { mark[j] = 1; break; } //j为0,说明所有时间都被占用,则扣除相应的钱数 if (j == 0) { m -= game[i].m; } } } cout << m << endl; return 0; }
例题2:删数
题目描述
输入一个高精度的正整数n(长度不大于240位),去掉其中任意 s个数字后剩下的数字按原左右次序将组成一个新的正整数,现求一种方案,使得新的正整数数值最小。
输入
第一行一个整数n。
第二行一个正整数s。
输出
输出一个数表示最小值,输出时忽略数字的前导零。
样例输入1
179566
4
样例输出1
15
样例输入2
903071
3
样例输出2
1
#include <iostream> #include <string> using namespace std; int main() { int n; string str; //用字符串读入 cin >> str >> n; for (int i = n; i > 0; i--) { //删除下标 int ind = str.size() - 1; for (int j = 0; i < str.size() - 1; j++) { //找到最大数,结束内层循环 if (str[j] > str[j + 1]) { ind = j; break; } } //进行删除 str.replace(ind, 1, ""); } //解决前置0问题 int f = 0; for (int i = 0; i < str.size(); i++) { if (str[i] != '0') f = 1; if (f == 1) cout << str[i]; } return 0; }
例题3:
问题:设有N个正整数,现在需要你设计一个程序,使他们连接在一起成为最大的数字。
例如3个整数 12,456,342 很明显是45634212为最大。
例如4个整数 342,45,7,98 显然为98745342最大。
例如3个整数 4671,467,3 显然46734671最大,这里有个陷阱,就是怎么安排4671和467的位置顺序。
程序要求:第一行输入整数N,接下来一行输入N个数字,最后一行输出最大的那个数字!
题目解析:看起来好像是找哪个数字的开头元素最大,然后按照大小顺序连在一起就OK了,但实际上要麻烦一些,比如如果N太大,比较起来就很麻烦,而且如果遇到像第三个例子那样的问题,你该怎么处理呢?
有一个办法是将数字转化为字符串,用strcmp比较a+b和b+a的大小,也就知道了谁应该排在前面。不过我这儿有一个更好的办法来实现这个程序。我们从这N个数中任取两个然后比较ab和ba的大小,如果ab>ba,那么就将a排在b之前,最后按照排好的这组数按从大到小的顺序输出。
#include<iostream> #include<cmath> using namespace std; bool compare(int Num1,int Num2) { int count1=0,count2=0; //分别记录Num1和Num2是几位数 int MidNum1 = Num1,MidNum2 = Num2; while( MidNum1 ) { ++count1; MidNum1 /= 10; } while( MidNum2 ) { ++count2; MidNum2 /= 10; } //pow(x,n)的意思是x的n次方 int a = Num1 * pow(10,count2) + Num2; //相当于把Num2接到了Num1后边 int b = Num2 * pow(10,count1) + Num1; //相当于把Num1接到了Num2后边 return (a>b)? true:false; //如果a>b就返回true } int main() { int N; cout<<"Please Enter The Number N: "<<endl; cin>>N; int *kk = new int [N]; //动态分配一个数组 for(int i=0;i<N;i++) cin>>kk[i]; int temp; for(int i=0;i<N-1;i++) //使用冒泡排序的模板 for(int j=0;j<N-i-1;j++) if(compare(kk[j],kk[j+1])) //此处稍微改造了一下 { temp = kk[j]; kk[j] = kk[j+1]; kk[j+1] = temp; } cout<<"The max number is:"; for(int i=N-1;i>=0;i--) cout<<kk[i]; cout<<endl; delete[]kk; //释放数组空间 return 0; }
