欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

通过减一或除以一个数将n变为1------贪心算法

程序员文章站 2022-06-03 14:40:08
...

初涉贪心算法,先将百度百科的定义贴下,留作慢慢体会:
贪心算法*(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解*。
贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
题目描述:
通过减一或除以一个数将n变为1------贪心算法
我原本的代码:

#include<stdio.h>
int main()
{
    long long a, b, n, k,x, cnt = 0;
    double t1, t2;
    scanf("%lld%lld%lld%lld", &n,&k,&a,&b);
    x = n;
    while (x != 1)
    {
        t1 = t2 = -1.0;
        t1 = 1.0/a;
        if (x%k == 0) t2 = 1.0*(x - x * 1.0 / k) /b ;
        if (t1 > t2) {
            x -= 1;
            cnt += a;
            continue;
        }
        x /= k;cnt += b;
    }
    printf("%lld", cnt);
    return 0;
}

分析:
最开始我的想法:按照性价比(也就是动态的用长度除以开销来计算)的思想,分两种情况:
(1)不能被k整除时,循环减一到整除,记录开销。
(2)可以被k整除时,计算减一和除以k的分别性价比,选优者记录开销。
这样做的结果是:测试数据没有太大问题,但是提交却总是Time Limit
分析下来原因有如下:
(1)未考虑特殊情况,即当 倍数k=1 的时候,只要是进行除法,n的值永远不变,这样不可能跳出循环。
(2)傻傻的用循环减一的方法来使n变得可以被k整除,进而讨论。这样反复循环,效率自然低得多。

改进的措施:
(1)考虑到 k==1 的情况,如果k==1,则此时只能用减一的方法来使n变为1
(2)对于循环减一直到整除的做法,改为一次性减到可以被整除
(3)可以被整除后,有两种策略 :a.直接除以k,得到 n/k ,减少的数目相当于 (n-n/k),开销为b; b.一直减一直到与(n-n/k)这个减少的数目相同为止,计算开销为 (n-n/k)*a通过比较前两种策略的优劣,可以加到cnt来得到局部最优解。
此时还存在一个问题,如果算到 n小于k时,循环开始时的减法会一直减到0(因为零除以任何非零数都得零),而我们期望得到的n为1,因此,这种情况需要另加判断,一旦算到这一步,就直接跳出循环,计算减到1所需的值加上即可。

改后代码:

#include<stdio.h>
int main()
{
    long long n, k, a, b;
    long long p, t1,t2,cnt = 0;
    scanf("%lld%lld%lld%lld", &n, &k, &a, &b);
    if (k == 1) {
        printf("%lld", (n - 1)*a);
        return 0;
    }
    while (n != 1)
    {
        if (n%k != 0) {     //直到可以整除再比较
            cnt += n%k *a;
            n-=n%k; //减到可以整除为止
        }   
        //如果减到可以整除时n仍大于1,就接着向下执行
        if (n > 1 && n%k == 0) {
            t1 = b; //直接除到的花销
            t2 = (n - n / k)*a; //一直减到刚才消去位置的花销
            if (t1 < t2) {
                cnt += t1;
            }
            else {
                cnt += t2;
            }
            n /= k;
        }
        if (n < k) break;
    }
    cnt += (n - 1)*a;
    printf("%lld", cnt);
    return 0;
}
相关标签: greedy algorithm