434
社区成员
发帖
与我相关
我的任务
分享一、 请用反证法证明“删数问题”的算法满足贪心选择性质(即设最优解不包含贪心选择,则可以通过转换找出一个更小的数,推出矛盾)
1、删数问题:
给定n位正整数a,去掉其中任意k≤n 个数字后,剩下的数字按原次序排列组成一个新的正整数。对于给定的n位正整数a和正整数
2、贪心策略:
(1) 从左到右依次遍历数字。
(2) 如果一个数字大于其右侧的数字,则右侧数字均向左一位(即删除该数字)。若遍历完数字后还未删完k个数字,则从后往前依次删除k个数字。
(3)重复步骤2,直到删除k个数字。
string str;
int k;
void deleteNum()
{ int i=0;
int len = str.length();
while(k)
{
while(str[i]<=str[i+1] && i<len-1) i++;
if (i < len - 1) { // 确保不会越界
for (int j = i; j < len - 1; j++) {
str[j] = str[j + 1];
}
}
len--;k--;i--;
}
int index=0;
for(index=0;index<len;index++)
{
if(str[index]!='0') break;
}
if(index>=len) cout<<"0"<<endl;
else{
for(int i=index;i<len;i++)
{
cout<<str[i];
}
}
}
3. 反证法证明:
反证法假设: 假设在给定的数字和需要删除的个数下,存在一个最优解 S,它不包含贪心策略的选择。
分析贪心策略的选择: 根据贪心策略,我们总是从左到右扫描数字,选择第一个满足 x>y(其中 y 是 x右边的数字)进行删除,因为这会最大程度减少数值的大小,从而使剩下的数字更小。因此,删除 x可以保证在当前位置的局部最优性,从而为后续的数字组合提供更好的基础。
假设的最优解 S 不包含贪心选择: 假设 S 选择保留了 x,而删除了其他数字。我们用 S’ 表示通过贪心策略得到的解。由于 S 和 S’ 的不同点在于 S 选择保留了 x,而 S’ 选择删除了 x,并且 x>y,那么 S 中的保留操作会导致后续的数字整体排列不如 S’ 小。
转换最优解 S 的结果: 如果我们在 S 中改为删除 x,则可以得到一个新的解 S’‘。由于 S’’ 采用了贪心策略,其后续的数字排列与 S’ 一致或更小。因此,S’’ 会比 S 小或相等,但绝不会更大。
矛盾的形成: 由于 S 被假设为最优解,但我们通过简单地将其转换为 S’’ 后得到一个更小或相等的数,这与 S 是最优解的假设矛盾。因此,假设不成立。
得出结论:最优解包含贪心策略。
举例说明:
假设我们有数字“178543”,需要删除k=2个数字。
贪心算法:贪心算法会删除'8',然后删除'7',得到“1543”。
假设的最优解(矛盾):
假设 S 选择不删除 8。这样的话,删除 2 个数字后,剩下的最小可能数字是 1843或更大。显然,这些数字都大于 1543。
假设 S 选择不删除 7。保留 7 后,剩下的最小数字可能是 1743或更大,显然也比 1543 大。
形成矛盾:
所有试图通过保留贪心策略中删除的数字(如 8、7)所构造的结果,都无法得到比 1543 更小的数字。这与假设 S 是最优解矛盾。因此,我们可以得出结论:假设不成立。
结论:
贪心选择的删除策略确保了每一步都在局部最优,最终形成的结果也是全局最优。如果存在其他策略比贪心策略更优,就会产生矛盾。因此,“删数问题”的贪心策略是正确的。因此,贪心算法没有产生最优解的假设导致了矛盾,贪心算法必须产生最优解。
2. 结合本章的学习,总结你对贪心法的体会和思考
贪心算法在每一步中做出局部最优的选择来解决问题,希望达到全局最优解。然而,它们并不总是有效。它们每次做选择时只考虑当前的最优解,并不会考虑全局,因此贪心策略的选择具有一定的局限性。我们在使用贪心算法时,需要考虑问题是否具有以下两个方面的性质:
(1)贪心选择性质:在每一步做出局部最优选择(即当前最小数字的选择)能够导致全局最优解。
(2)最优子结构性质:问题的最优解可以由其子问题的最优解组合而成。
贪心算法在一定情况下提供了一种简单有效的方法,但总是需要仔细考虑问题的性质及构成,不能盲目使用贪心算法。