洛谷P5019 铺设道路的递归和贪心题解

写了一下午代码越发地觉得自己是个傻逼
这和这篇博客并没有什么关系只是单纯地感叹一下

这是一道2018、2013以及USACO都考过的题目,非常地经典,这里提供递归和贪心的两种题解。

1、递归
题目很简单,就是填坑嘛,能一起填的就一起填呗,这样省事,然后依次找可以一起填的子区间填就是了,发现处理过程非常相似就想到递归咯。
这道题如果用暴力的话会超时,这里把能一起填的直接加就会简便一些,时间复杂度大致O(nlogn)
具体细节见代码:

#include <cstdio>
#include <iostream>
using namespace std;
int n, ans;
int a[100005];

int findminn(int l, int r)//找出从left到right中的最小值
{
    int minn = 2147483647;
    for(int i = l; i <= r; i ++)
    {
        if(a[i] < minn) minn = a[i];
    }
    return minn;
}

void printline()//实际代码中没啥用,当初为了debug写的
{
    for(int i = 1; i <= n; i ++) printf("%d ", a[i]);
    printf("\n");
}

void search(int l, int r)
{
    int minn, flag1, flag2;
    if(l == r)//递归结束条件
    {
        ans += a[l];
        return ;
    }
    minn = findminn(l , r);
    ans += minn;
    for(int i = l; i <= r; i ++) a[i] -= minn;
    flag1 = l;
    while(flag1 <= r)
    {
        while(!a[flag1] && flag1 <= r) flag1 ++;
        flag2 = flag1;
        while(a[flag2] && flag2 <= r) flag2 ++;
        flag2 --;//注意这里要减1才能获取目标区间
        if(flag2 <= r && flag1 <= r) search(flag1, flag2);
        flag1 = flag2 + 1;//为找下一个区间做准备,不加这个会死循环
    }
    return ;
}

int main()//main函数不超10行,我们老师教我们的
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    search(1, n);
    printf("%d\n", ans);
    return 0;
}

2、贪心

刚刚的想法是我看了题后自己尝试的,看了大佬的题解才发现贪心的真正牛逼之处:
如果大坑旁边还有个小坑,填大坑的时候就顺便把小坑也填了
(数组可能比较大我就开vector了)

#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
int n, ans;
int main()//别问,问就是main函数不超过10行
{
    scanf("%d", &n);
    vector<int> a(n + 5, 0);
    for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
    for(int i = 2; i <= n; i ++) 
    {
        if(a[i] > a[i-1]) ans += a[i] - a[i-1];
    }
    printf("%d\n", ans + a[1]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值