贪心算法分析

1、硬币问题

题目:
有1元、5元、10元、100元、500元的硬币各C1、C5、C10、C50、C100、C500枚。现在要用这些硬币来值付A元,最少需要多少枚硬币?假设本题至少存在一种值付方案。

限制条件:
0<=C1,C5,C10,C50,C100,C500<=10^9
0<=A<=10^9

输入样例:
C1=3,C5=2,C10=1,C50=3,C100=0,C500=2,A=620
输出样例:
6(500元1枚,50元2枚,10元1枚,5元2枚,合计6枚)

该问题中,我们优先使用面值较大的硬币。

#include<iostream>

using namespace std;

const static int v[6] = { 1,5,10,50,100,500 };

int C[6];
int count[6];
int A;

void init(){
    for(int i=0;i<6;i++){
        cin>>C[i];
    }
    cin>>A;
}

void sove(){
    int ans=0;
    for(int i=5;i>=0;i--){
        int temp=min(A/v[i], C[i]); //第i种硬币最多可以使用A/v[i]个,C[i],表示第i种硬币的个数,说以取两者较小值
        A-=temp*v[i];
        count[i]=temp;
        ans+=temp;
    }
    cout<<ans<<"(";
    for(int i=5;i>=0;i--){
        cout<<v[i]<<"元"<<count[i]<<"枚,";
    }
    cout<<")";
}

int main(){
    init();
    sove();
    return 0;
}

1、区间问题

问题:区间调度问题
现在又n项工作,每项工作分别在Si时间开始,在ti时间结束。对于每项工作,你都可以选择参与与否。如果选择了参与,那么自始至终都必须全程参与。此外,参与工作的时间段不能重叠(即使是开始的瞬间和结束的瞬间也是不允许的)。
限制条件:
1<=N<=100000
1<=si<=ti<=10^9

输入样例:
n=5, s={1,2,4,6,8}, t={3,5,7,8,10}
输出样例:
3(选取工作1、3、5)

算法分析:在可选工作中吗,每次都选择结束时间最早的工作。

设计代码如下:

#include<iostream>
#include<algorithm>

using namespace std;

#define MAX_N 100000

//用于对工作排序
pair<int, int> itv[MAX_N];
int N, S[MAX_N], T[MAX_N];

void init(){
    cin>>N;
    for(int i=0;i<N;i++){
        cin>>S[i];
    }

    for(int i=0;i<N;i++){
        cin>>T[i];
    }
}

void sove(){
    //对pair排序,T放入first,S放入second
    for(int i=0; i<N; i++){
        itv[i].first=T[i];
        itv[i].second=S[i];
    }
    sort(itv, itv+N); //按t(工作结束时间)排序
    int ans=0,t=0;
    for(int i=0; i<N ; i++){
        if(t<itv[i].second){
            ans++;
            t=itv[i].first;
        }
    }
    cout<<ans<<endl;
}

int main(){
    init();
    sove();
    return 0;
}

3、字典最小问题

题目:Best Cow Line(POJ 3617)
给定长度为N的字符串S,要构造一个长度为N的字符串T。T是一个空串,随后反复进行下列任意操作。
从S头部删除一个字符,加到T的尾部
从S尾部删除一个字符,加到T的尾部
目标是要构造字典序尽可能小的字符串T。
限制条件:
1<=N<=2000
字符串S只包含大写英文字母

输入示例:
N=6;
S=”ACDBCB”
输出示例:
ABCBCD

操作过程示意图:
操作过程

分析:

  • 不断取S的开头和末尾中较小的一个字符放入到T的末尾
    • 但是这样做会出现一个问题,如果S开头和末尾相同,接下来一个也相同,再接下一个也相同,……. 。这样的化难道需要我们依次进行判断怕然比较大小吗?其实不需要这样做,我们可以利用字符串比大小的原理来设计算法。
  • 比较字符串S和S‘ 的大小
  • 将较小的字符串的首字母移入T

代码如下所示:

#include<iostream>
#include<algorithm>
#include<string>

using namespace std;
int n;
string S;
string T="";
string SR;

void sove(){
    cin>>n;
    cin>>S;
    int leng=S.length();
    SR=S.substr(0, leng/2);
    reverse(S.begin(),S.end());
    if(leng%2!=0)
        S=S.substr(0,leng/2+1);
    else S=S.substr(0,leng/2);


    for(int i=0;i<leng;i++){
        if(SR.length()==0){
            T.append(S);
            break;
        }
        if(S.length()==0){
            T.append(SR);
            break;
        }
        if(SR<S){
            T.append(SR.substr(0,1));
            SR=SR.substr(1);
        }else{
            T.append(S.substr(0,1));
            S=S.substr(1);
        }
    }
    cout<<T;
}

int main(){
    sove();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_28120673/article/details/81021394