概念:在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。
算法特征:选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
样例:
1.翻硬币问题(https://www.dotcpp.com/oj/problem1453.html):不必太过细致考虑,题目中所说最少次数其实就是依照最基本的规则,对每个硬币进行依次判断,当第i个位置的字符与模板串不相同时,对此位以及第i+1位进行取反。代码如下(错误率50%)
错误代码:
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string s1,s2;
cin>>s1;
cin>>s2;
int len = s1.length();
char a[100]={0};
s1.copy(a,len,0);
char b[100]={0};
s2.copy(b,len,0);
int sum=0;
for(int i=0;i<len;i++)
{
if(a[i]==b[i])
continue;
cout<<i<<" ";
sum++;
b[i]=a[i];
if(b[i+1]=='*')
b[i+1]='o';
if(b[i+1]=='o')
b[i+1]='*';
}
cout<<endl<<a<<endl<<b;
cout<<sum<<endl;
return 0;
}
错误原因:没有认真读题,题目中前一个是初始状态串,后一个是目标串,上面错误的代码是将b串进行更改,所以测试输出时两个串完全一样,但得到的总次数sum、却不同!!!
反思:认真读题!!!
翻硬币正确代码:
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string s1,s2;
cin>>s1>>s2;
char a[1000],b[1000];
int len=s1.length();
s1.copy(a,len,0);
s2.copy(b,len,0);
int sum=0;
for(int i=0;i<len-1;i++)
{
if(a[i]==b[i])
continue;
else
{
sum++;
a[i]=b[i];
if(a[i+1]=='*')
a[i+1]='o';
else
a[i+1]='*';
}
}
cout<<sum;
return 0;
}
2.打水问题(https://www.dotcpp.com/oj/problem1523.html):从小到大顺序排列后,采用依次分队的方法,这样可保证总时间最短。在代码实现过程中,注意对数组进行间隔固定个数取数的算法。
#include <iostream>
#include <string>
using namespace std;
int main ()
{
int N,M;
cin>>N>>M;
int peo[1000];
int t;
for(int i=0;i<N;i++)
cin>>peo[i];
for(int i=0;i<N;i++)
{
for(int j=i;j<N;j++)
{
if(peo[i]>peo[j])
{
t=peo[i];
peo[i]=peo[j];
peo[j]=t;
}
}
}
long long sum=0;
int l=0;
for(int i=0;i<M;i++)
{
l=0;
for(int j=i;j<N;)
{
l=peo[j]+l;
sum=sum+l;
j=j+M;
}
sum=sum-l;
}
cout<<sum;
return 0;
}