贪心


贪心:贪婪算法是一种算法范例,它遵循在每个阶段做出局部最优选择的启发式求解方法,目的是寻找到一个全局最优解。

用处:①活动安排    

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

 

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM