贪心算法:贪心法是一种策略,首先是要遵循某种特定的规则来选取“当前”最优解,对于一道题的思路有多种,也就是说要在众多思路的计算方法中选取最正确的,所以首先要证明贪心的正确性,通常使用反证法和归纳法进行,举一个反例数据,若反例存在,则贪心错误。
例题1(硬币问题):有面值为 1元、5元、10元、50元、100元、500元的硬币中数量各为ai(i=1,2,3,4,5)枚硬币,给定应支付的钱数,求最少需要的硬币,
那么根据尝试要用最少的数量买最多的东西,肯定是花面值更大的硬币,
例题2 (区间调度)诸多涉及区间冲突之类问题都会用到贪心法,假设有n项工作每项工作从ai开始到bi结束,可选择这些工作并且中途不能中断,同时间段内的工作不可同时进行,也就是说只有某项工作结束才能继续下一份工作,于是要求你求出能参加的最多工作,
于是我们想到能参加最多工作是不是求每个工作时间最短的,理论上如果时间短,那么可参加的就多,但是还有一种情况是每项工作的时间是可能存在重叠的,如果说只有某项工作结束才能继续下一项工作那么又会想到如果工作的时间结束的最早,继续下一份工作的开始时间就越早,数量也自然就多,所以贪心算法就是从这几个理论中选取最正确的理论,这个理论就是贪心所遵循的一种规则,
#include <bits/stdc++.h>
using namespace std;
#define maxn 1000010
struct competation {
int ft; //左区间
int lt; //右区间
}a[maxn];
bool cmp(competation p,competation q){
return p.lt<q.lt; //按照右区间小的顺序排列,也就是结束时间早
}
int main()
{int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i].ft>>a[i].lt;
}
sort(a+1,a+1+n,cmp);
int ans=0,lst=0;
for(int i=1;i<=n;i++){
if(a[i].ft>=lst){
ans++;lst=a[i].lt;
//更新结束时间,为了与每项工作的开始时间比较,只有早于开始时间才能开始下一个
}
}
cout<<ans;
return 0;
}
例3.删数处理
键盘输入一个高精度的正整数 N(不超过 250250 位),去掉其中任意 k 个数字后剩下的数字按原左右次序将组成一个新的非负整数。编程对给定的 N 和 k,寻找一种方案使得剩下的数字组成的新数最小
要想数最小那么肯定是要让高位的数越小,也就是说应该要让高位中数字大的删掉,那数字大的范围是多少呢,那就要进行比较,如176238 ,1 首先第一感觉删除的是7,如果判定7为最大,那他是和谁比较的? 从多组数据中得出应和低位的比较,但是还有类例子是18,1和123,1第一组删除8,第二组删除3,所以假如给定的数字中没有高位值大于低位值的数就要删除最后一位,
//在测试数据中会有类似10086 这种删掉1后具有前导0的数据,要考虑去掉,以及最后数据的10 1 要输出0.
#include<bits/stdc++.h>
using namespace std;
string s;
int k;
int main()
{
cin>>s;
cin>>k;
int f[300];
int len=s.length();
for(int i=0;i<len;i++){
f[i]=s[i]-'0'; //使用数组转存
}
int l=k; //记录实际删除数字
for(int p=1;p<=k;p++){ //在指定次数内删除数字,要循环次数
for(int i=0;i<len-1;i++) //扫描,从头开始对数组扫描
{
if(f[i]>f[i+1]){
if(l==0) break;//删完了就退出
for(int j=i;j<len-1;j++){
f[j]=f[j+1];//所谓的删数字就是将数组前移一位
}
len--;//长度减小
l--;//实际次数减小
break;//减小一次本次扫描就扫描完了
}
}
}
int c=0;
while (f[c]==0){
c++; //删除前导0,让标签指针指向有效的开头数字
}
if(l!=0){ // l不等于0说明在指定次数内未能删除有效数字,
while(l--)
{
len--;//所以一定是没有符合条件的数(前数大于后数),那么就删除最后一位
}
}
if(len<c)
//此时说明是类似000这类情况所以指针一直指向大于len的位置,就直接输出0就行,对应数据10 1
{
cout<<"0"<<endl;
return 0;
}
for(int g=c;g<len;g++)
cout<<f[g];
return 0;
}