贪心算法采用自顶向下,以迭代的方法做出相继的贪心选择,每做一次贪心选择就将所求问题简化为一个规模更小的子问题,通过每一步贪心选择,可得到问题的一个最优解,虽然每一步上都要保证能获得局部最优解,但由此产生的全局解有时不一定是最优的,所以贪婪法不要回溯。能够用贪心算法求解的问题一般具有两个重要特性:贪心选择性质和最优子结构性质。
参考:http://babybandf.blog.163.com/blog/static/61993532010112923767/
[例1]删数问题[B][/B]
试题描述 键盘输入一个高精度的正整数N(不超过240位),去掉其中任意S个数字后剩下的数字按左右次序组成一个新的正整数。对给定的N和S,寻找一种删数规则使得剩下得数字组成的新数最小。
试题背景 此题出自NOI94[B][/B]
试题分析 这是一道运用贪心策略求解的典型问题。此题所需处理的数据从表面上看是一个整数。其实,大家通过对此题得深入分析便知:本题所给出的高精度正整数在具体做题时将它看作由若干个数字所组成的一串数,这是求解本题的一个重要突破。这样便建立起了贪心策略的数学描述。
每次删除一个数字,选择一个使剩下的数最小的数字作为删除对象,之所以选择这样”贪心”的操作,是因为删S个数字的全局最优解包含了删一个数字的子问题的最优解.
当S=1时,在N中删除哪一个数字能达到最小的目的?从左到右每相邻的两个数字比较:若出现左边大于右边,则删除左边的大数字.若不出现降序排列,即所有数字全部升序,则删除最右边的大数字.
当S>1,按上述操作一个一个删除,删除一个达到最小后,再从头即从串首开始,删除第2个,依次分解为S次完成.
若删除不到S个后已无左边大于右边的减序,则停止删除操作,打印剩下串的左边L-S个数字即可(相当于删除了若干个最右边的大数字,这里L为原数字N的位数).
#include<iostream>
#include<string>
using namespace std;
int main()
{
string n;
int s,i,x,l,m;
while(cin>>n>>s)
{
i=-1,m=0,x=0;
l=n.length();
while(x<s&&m==0)
{
i++;
if(n[i]>n[i+1])//出现递减,删除递减的首数字
{
n=n.erase(i,1);
x++;// x统计删除数字的个数
i=-1;//从头开始查递减区间
}
if(i==l-x-2&&x<s)
m=1;//已经无递减区间,m=1脱离循环
}
cout<<n.substr(0,l-s+x);//只打印剩下的左边l-(s-x)个数字
}
}