贪心算法
贪心算法(Greedy algorithm)(又称贪婪算法)是一种对某些求最优解问题的更简单、更迅速的设计技术。用贪心法设计算法的特点是一步一步地进行,常以当前情况为基础根据某个优化测度作最优选择,而不考虑各种可能的整体情况,它省去了为找最优解要穷尽所有可能而必须耗费的大量时间。
我们先来看题道题:
Lougu P2695 骑士的工作
(题目自己看,不讲了)
很显然,要使钱消耗最少且把恶龙杀死(除了砍不死龙的情况),就必须找到能砍死恶龙头的勇士且这个勇士是在所有能砍死恶龙的勇士中能力最小的,因为如果用了其他能力比他大勇士,就一定会使雇用的总金币数增加,也可能会砍不死龙。所以,运用这个贪心策略就可以实现钱的最优化和杀龙的最优化。
因此,我们可以先将龙头的砍杀与勇士的能力进行从小到大排序,然后我们运用贪心算法,从小到大将龙头的砍杀难度与勇士的能力一一比较,如果能砍掉,就砍,并累加金币数到sum,如果砍不掉,就换下一位勇士,直到勇士没了或龙头没了,最后,如果是勇士没了,就输出“youdied!”,否则,就输出金币最优质sum。
于是,就有了以下代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
inta[20001],b[20001]; //a数组记录龙头,b数组记录勇士
intn,m;
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=m;i++) cin>>b[i];
sort(1+a,1+a+n);
sort(1+b,1+b+m);
inti=1,j=1;
intsum=0;
while(i!=n+1 && j!=m+1) //判断是否有龙头用尽或勇士用尽
{
if (b[j]>=a[i]) //判断能否砍掉龙头
{
sum+=b[j];
j++;
i++;
}
else j++;
}
if(j==m+1) cout<<"you died!"; //砍不掉龙
else cout<<sum; //能砍掉龙
return0;
}
再来一道:
Lougu P1106 删数问题
(题目自己看,也不讲了)
看了这道题,第一感觉就是用字符串读入,再每次找到最大的数删去,如果你那么做了,那么你样例也会过,但是,你在测评中——听取WA声一片。为什么呢?我们来看一组数据。
Input :
1357699
1
很显然,如果用原来的方法,就会输出135769,但是这个样例正确输出应该是135699。
于是,我们有了一种新策略,把这个数从最小位到最大位枚举,如果后面的数比前面的数小,那么就删去前面的数(不下降)。
但是,这道题目还有许多细节要处理:
1. 当改完这个数后,如果有前导0,如果有前导0,那么必须要删去。
2. 当这个数只有0时,不能将0全部删完,要留下一个。
3. ……
代码如下:
#include <bits/stdc++.h>
using namespace std;
int main()
{
intn,m,i,j;
strings;
cin>>s;
cin>>n;
for(i=1;i<=n;i++)
{
for(j=0;j<=s.length()-1;j++) //枚举
if(s[j]>s[j+1]) //删数操作
{
s.erase(j,1);
break;
}
}
while(s[0]=='0' && s.length()>1) //判断前导0
s.erase(0,1);
cout<<s;
return0;
}
最后一道:
LouguP1090 合并果子
(.…..)
这道题,用模拟肯定是不行的,显而易见。
但是我们发现,只有将两堆最小的合并成一堆,这样的体力消耗值才是最小的,于是,咱们可以这么想,咱们将这对果子进行n减一次的操作,每次将最小的那两堆合并在一起,然后将这些数重新快速排序,然后再进行这样的操作,这样得出的总体力消耗值一定是最小的。
代码就是这样子:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,m,i,j,sum=0;
int a[10000];
cin>>n;
for (i=1;i<=n;i++)
cin>>a[i];
sort(1+a,n+a+1); //我们的Cpp真是个好东西呀,快排这么方便,都不用像pascal里面那样打那么长的快排代码。
for (i=1;i<=n-1;i++)
{
sum=sum+a[i+1]+a[i]; //累加
a[i+1]=a[i]+a[i+1]; //合并
sort(i+1+a,a+n+1);
}
cout<<sum;
return 0;
}
小小蒟蒻,只能讲一些简单题,请谅解。
崇拜大佬!!!