Uva 1617 有时候题目可能没有你想得那么复杂...

一、题意

给你n条线段(线段端点为整数,n<=100000),输入保证线段间没有包含关系,且保证有解。
现在要求将每条线段截取长度为1的一小段,使得截取后的所有线段之间的空隙数目最少。
输出空隙的最少数目。

二、解析

  • 一开始用了一种比较复杂的方法:
    将所有线段按右端点排序后,每个线段尽量靠左边选取长度为1的片段,并维护一个remain值,表示该长度为1的片段右侧的空余长度(也就是可以动态右移多少长度);还要维护一个cur值,表示当前已经选取的1片段的最右端位置。然后每次当发现当前线段与上一线段的1片段(cur值)之间有空隙时,首先检查remain能否填充这个空隙,若能,则将该空隙填充;若不能则说明这个空隙必须存在,即ans++。每次判定完一个片段需要更新remain值、cur值。
    这算是一种比较完备的思路,具体见后面代码。

  • 后来在网上发现一种简单一些的思路:
    由于题目中已经保证有解,因此其实根本不需要判定是否放得下,只需要执行贪心策略即可:即还是按照线段的右端点排序,然后第一个线段选取最靠右边的长度为1的片段(贪心),然后后续线段就紧靠着选取即可。若发现无法紧靠,即必然有空隙,则ans++;否则就一定能放得下。这种方法就只需要维护一个cur值表示当先选取的1片段得最右端即可。
    唯一要细节处理得就是,若当前线段与已选取1片段得最右端重合,则不需要改变cur值,因为题目保证有解,所以这里隐含得操作实际上是,将前面的所有片段左移1个单位,然后再将当前1片段放在这里。

三、代码

  • 比较完备的代码
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1e5 + 5, INF = 1 << 30;
struct section{
    int l, r;
    bool operator < (const section& rhs) const {
        return r < rhs.r || r == rhs.r && l < rhs.l;
    }
} a[maxn];
int kase, n;

int main(){
    cin >> kase;
    while(kase --){
        cin >> n;
        for(int i = 0; i < n; i ++) cin >> a[i].l >> a[i].r;
        sort(a, a + n);
        int ans = 0, remain = INF, cur = a[0].l;
        for(int i = 0; i < n; i ++){
            if(cur + 1 > a[i].r) ans ++, cur = a[i].l + 1;
            else if(cur < a[i].l){
                if(a[i].l - cur <= remain) remain -= a[i].l - cur;
                else ans ++, remain = INF;
                cur = a[i].l + 1;
            }
            else cur ++;
            remain = min(remain, a[i].r - cur);
        }
        cout << ans << endl;
    }
}
  • 比较取巧的代码
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 100000 + 5;
struct section {
    int l, r;
    bool operator < (const section& rhs) const {
        return r < rhs.r || r == rhs.r && l < rhs.l;
    }
} a[maxn];
int kase, n;

int main() {
    cin >> kase;
    while(kase --) {
        cin >> n;
        for(int i = 0; i < n; i ++) cin >> a[i].l >> a[i].r;
        sort(a, a + n);
        int cur = a[0].r, ans = 0;  // 贪心:第一个片段靠最右边放,之后的依次紧靠
        for(int i = 1; i < n; i ++) {
            if(a[i].l > cur) ans ++, cur = a[i].r;
            else if(a[i].r == cur) continue;
            else cur ++;  // 由于线段端点为整数,所以只要右端不相等,就至少大1,一定足够放
        }
        cout << ans << endl;
    }
}

四、归纳

  • 要仔细看清楚题目,说不定题目没有你想的那么复杂....
  • 大多数时候,题目的输入全为整数值,这代表“偏移量”等要么为0,要么为1,这可能是简化题意的关键
Re:从零开始的刷题生活 文章被收录于专栏

一起来重刷题叭~ 由于精力有限,题意只说大概,题目细节可以点击vjudge链接查看。 题目以紫薯中的Uva例题/习题为主,有时候有些比较经典的算法也会特意从其它OJ上找题,并不一定出现在紫薯上。 噢,紫薯指——《算法竞赛入门经典(第2版)》by 刘汝佳 喜欢的小伙伴点个赞呗?不然我只能认为一直只有我一个人在自娱自乐orz....

全部评论

相关推荐

避坑恶心到我了大家好,今天我想跟大家聊聊我在成都千子成智能科技有限公司(以下简称千子成)的求职经历,希望能给大家一些参考。千子成的母公司是“同创主悦”,主要经营各种产品,比如菜刀、POS机、电话卡等等。听起来是不是有点像地推销售公司?没错,就是那种类型的公司。我当时刚毕业,急需一份临时工作,所以在BOSS上看到了千子成的招聘信息。他们承诺无责底薪5000元,还包住宿,这吸引了我。面试的时候,HR也说了同样的话,感觉挺靠谱的。于是,我满怀期待地等待结果。结果出来后,我通过了面试,第二天就收到了试岗通知。试岗的内容就是地推销售,公司划定一个区域,然后你就得见人就问,问店铺、问路人,一直问到他们有意向为止。如果他们有兴趣,你就得摇同事帮忙推动,促进成交。说说一天的工作安排吧。工作时间是从早上8:30到晚上18:30。早上7点有人叫你起床,收拾后去公司,然后唱歌跳舞(销售公司都这样),7:55早课(类似宣誓),8:05同事间联系销售话术,8:15分享销售技巧,8:30经理训话。9:20左右从公司下市场,公交、地铁、自行车自费。到了市场大概10点左右,开始地推工作。中午吃饭时间大约是12:00,公司附近的路边盖饭面馆店自费AA,吃饭时间大约40分钟左右。吃完饭后继续地推工作,没有所谓的固定中午午休时间。下午6点下班后返回公司,不能直接下班,需要与同事交流话术,经理讲话洗脑。正常情况下9点下班。整个上班的一天中,早上到公司就是站着的,到晚上下班前都是站着。每天步数2万步以上。公司员工没有自己的工位,百来号人挤在一个20平方米的空间里听经理洗脑。白天就在市场上奔波,公司的投入成本几乎只有租金和工资,没有中央空调。早上2小时,晚上加班2小时,纯蒸桑拿。没有任何福利,节假日也没有3倍工资之类的。偶尔会有冲的酸梅汤和西瓜什么的。公司的晋升路径也很有意思:新人—组长—领队—主管—副经理—经理。要求是业绩和团队人数,类似传销模式,把人留下来。新人不能加微信、不能吐槽公司、不能有负面情绪、不能谈恋爱、不能说累。在公司没有任何坐的地方,不能依墙而坐。早上吃早饭在公司外面的安全通道,未到上班时间还会让你吃快些不能磨蹭。总之就是想榨干你。复试的时候,带你的师傅会给你营造一个钱多事少离家近的工作氛围,吹嘘工资有多高、还能吹自己毕业于好大学。然后让你早点来公司、无偿加班、抓住你可能不会走的心思进一步压榨你。总之,大家在找工作的时候一定要擦亮眼睛,避免踩坑!———来自网友
qq乃乃好喝到咩噗茶:不要做没有专业门槛的工作
点赞 评论 收藏
分享
点赞 评论 收藏
分享
一表renzha:你点进去没打招呼他也会有提示的,之前我点进美的,还没打招呼,他马上给我发了不太合适哦
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务