貪心


貪心:貪婪算法是一種算法范例,它遵循在每個階段做出局部最優選擇的啟發式求解方法,目的是尋找到一個全局最優解。

用處:①活動安排    

    設有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