【算法学习笔记】37.区间合并问题 SJTU OJ 1262 Milking Cow

Description

瓦特尔,阿隆索,汉密尔顿在F1上海站进行比赛,每人必须进维修站更换轮胎一次(谁出的无聊规定?!),而且只能进维修站一次。

阿隆索在20秒进站换胎,一直到90秒出站。瓦特尔在60秒开始进站,在 130秒结束。汉密尔顿在160秒开始220秒结束。期间最长的至少有一个车手在维修区的连续时间为110秒(从20秒到130秒),而最长的无人在维修区的连续时间(从有人进维修站开始一直到出维修站)为30秒(从130秒到160秒)。

假设现在又进行了一场有N个车手的比赛,你的任务是编一个程序,读入一个有N个车手(1 <= N <= 5000)进N次站的工作时间列表,计算以下两点(均以秒为单位):

最长至少有一人在维修站内的时间段。

最长的无人在维修站的时间段。(从有人进站开始算起)

Input Format

第1行:一个整数N。

第2至第N+1行:每行两个小于1000000的非负整数,表示一个车手的进站时刻与出站时刻。

Output Format

一行,两个整数,即题目所要求的两个答案。

Sample Input

3
200 900
600 1300
1600 2200

Sample Output

1100 300

最直觉的想法是把可以合并的连续有车的时间合并起来,算作一个时间段,构建一个只有不重合且不连续的若干个区间,然后就可以很容易的得到答案了.

构建的时候,可以考虑首先把这些区间(按照开始时间的先后)排序,方便逻辑处理.在合并的过程中,对两个区间进行分类讨论. 有交叉(相等) 包含 或者根本无交集.

#include <iostream>
#include <stdlib.h>
using namespace std;

struct carPeriod
{
    int start;
    int end;
};
carPeriod cars[5001];
carPeriod newcars[5001];

int cmp_carperiod_1(const void* _a, const void* _b){
    carPeriod* a = (carPeriod*) _a;
    carPeriod* b = (carPeriod*) _b;
    return (*a).start - (*b).start;
}
int main(int argc, char const *argv[])
{

    int N;cin>>N;
    for (int i = 0; i < N; ++i)
        cin>>cars[i].start>>cars[i].end;
    int maxIN=0, maxOUT=0;
    qsort(cars, N, sizeof(carPeriod),cmp_carperiod_1);//根据进入的时间排序
    int newN = 0;//新时间段的个数

    newcars[newN].start = cars[0].start; //第一个时间段
    newcars[newN].end = cars[0].end;

    //目标: 把所有的有交集的时间段组合起来
    for (int i = 1; i < N; ++i)
    {
        if(cars[i].start <= newcars[newN].end and cars[i].end >= newcars[newN].end){//交叉关系
            newcars[newN].end = cars[i].end;//接上
        }
        else if(cars[i].start >newcars[newN].start and cars[i].end<newcars[newN].end)
            continue;//包含关系 不进行任何操作
        else{
            newN++;//无交集 建立新的片段
            newcars[newN].start = cars[i].start;
            newcars[newN].end = cars[i].end;
        }
    }
    // cout<<"------"<<endl;
    // for (int i = 0; i <= newN; ++i)
    //     cout<<newcars[i].start<<" "<<newcars[i].end<<endl;
    // cout<<"------"<<endl;
    //maxIN
    for (int i = 0; i <= newN; ++i)
    {
        int period = (newcars[i].end - newcars[i].start);
        if( period > maxIN )
            maxIN = period;
    }
    //maxOUT
    for (int i = 1; i <= newN; ++i)
    {
        int interval = newcars[i].start - newcars[i-1].end;
        if( interval > maxOUT )
            maxOUT = interval;
    }
       cout<<maxIN<<" "<<maxOUT<<endl;
    return 0;
}

/*
4
2 5
10 101
10 101
80 102
*/

				
时间: 2024-08-03 22:14:20

【算法学习笔记】37.区间合并问题 SJTU OJ 1262 Milking Cow的相关文章

【算法学习笔记】43.动态规划 逆向思维 SJTU OJ 1012 增长率问题

1012. 增长率问题 Description 有一个数列,它是由自然数组成的,并且严格单调上升.最小的数不小于S,最大的不超过T.现在知道这个数列有一个性质:后一个数相对于前一个数的增长率总是百分比下的整数(如5相对于4的增长率是25%,25为整数:而9对7就不行了).现在问:这个数列最长可以有多长?满足最长要求的数列有多少个? Input Format 输入仅有一行,包含S和T两个数( 0<S<T≤200000 ). 30%的数据,0<S<T≤100 : 100%的数据,0&l

【算法学习笔记】50.字符串处理 SJTU OJ 1361 丁姐的周末

Description 丁姐来到了神秘的M78星云,为了成为和凹凸曼一样强大的男人有朝一日回到地球拯救世界,丁姐开始了刻苦的学习.但丁姐先要知道在M78星云上一周有多少天,这样他才能知道什么时候是周末可以带妹子出去玩.他找到一个老凹凸曼,但是老凹凸曼自己记性不太好,偶尔会告诉他错误的信息. 凹凸曼会告诉丁姐如下格式的信息: Today is xxxday. Yesterday was yyyend. Tomorrow will be zzzday. 规则1: xxx/yyy/zzz为任意字符串,

【算法学习笔记】60.经典动态规划 SJTU OJ 1370 赫萝的桃子

Description 赫萝最喜欢吃蜂蜜腌渍的桃子.然而她能够得到的桃子有限,因此赫萝必须精打细算.赫萝在b天内可以得到a个桃子,每天赫萝至少吃一个桃子,她想知道她在a天内有多少种吃桃子的方法.吃桃子的顺序并不重要,也就是说赫萝认为“第一天吃一个桃子第二天吃两个桃子”和“第一天吃两个桃子第二天吃一个桃子”算一种方法. Input Format 每个测试点有多组测试数据. 第一行一个数n,表示测试的数量. 接下来n行每行两个数a, b(a>b). Output Format 输出n行,每行一个数,

【算法学习笔记】87. 枚举路径 SJTU OJ 1999 二哥找宝藏

这个题只用BFS来搜索一次会很麻烦, 因为每次经过一个宝藏之后,要把所有的vis重置(因为可以重复经过同一点, 但是这样会有很多不必要的路径) 看题目的暗示 最多只有5个宝藏  我们要把所有的宝藏收集齐全, 如果确定了收集的顺序, 那么也就确定了路径 那么可以知道 A55的排列一共是120种路径 遍历起来毫无压力 我们枚举所有宝藏的全排列, 然后从起点开始走, 记录整个路径的步数, 最后取最小值即可. 这里生产全排列的方法利用了 STL的next_permutation函数 非常爽....(要引

【算法学习笔记】70.回文序列 动态规划 SJTU OJ 1066 小M家的牛们

这个题很多地方暗示了DP的路径. 我们处理时,dp[i][j]可以认为是从i坐标到j坐标的序列达到回文效果需要的最小代价,以此向外扩展,最终得到dp[0][M-1]就是结果. 我们要注意到处理dp[i][j]时,我们需要知道 dp(i+1,j-1)的结果,所以i必须降序,j必须升序,才能保证在计算dp(i,j)时,可以利用已经计算过的结果. 所以 i应该从M-2 到 0 递减 j在内层 从i+1到M-1 递增 在处理dp(i,j)时,第一要看name[i]和name[j]是否相等,如果相等的话,

【算法学习笔记】34.高精度除法 SJTU OJ 1026/1016

高精度除法, 这个和加减乘一样,我们都要从手算的角度入手.举一个例子,比如 524134 除以 123.结果是4261 第一位4的来源是 我们把 524和123对齐,然后进行循环减法,循环了4次,余32,将32134的前三位321继续和123对齐,循环减法2次,余75,把7534的前三位753和123对齐,循环减法6次,余15,将154和123对齐,只能减1次,所以结果是4 2 6 1. 把上述过程程序化 1.把A,B两个数存入char数组 0下标表示的是最高位2.把A的前lenB位和B对齐进行

【算法学习笔记】64. 枚举法 SJTU OJ 1381 畅畅的牙签

枚举法就好了,推理很麻烦,感觉也做不出来. 创造一个结构体,一个是真实的数,一个是花费的牙签数. 构建一位数,两位数,三位数即可. #include <iostream> #include <vector> using namespace std; //从0到9耗费的牙签数 int cost[10]={6,2,5,5,4,5,6,3,7,6}; struct num { int n;//用于计算的数 int c;//耗费的牙签 }; num v[100000]; int main(

带花树算法学习笔记

带花树算法学习笔记 难得yyb写了一个这么正式的标题 Q:为啥要学带花树这种东西啊? A:因为我太菜了,要多学点东西才能不被吊打 Q:为啥要学带花树这种东西啊? A:因为我做自己的专题做不动了,只能先去"预习"ppl的专题了 Q:为啥要学带花树这种东西啊? A:因为可以用来做题啊,比如某WC题目 先推荐一个很皮很皮的带花树讲解: 戳这里嗷 QaQ 言归正传 带花树的算法用来解决一般图的最大匹配问题 说起来,是不是想起来网络流里面的最小路径覆盖? 或者二分图的最大匹配的问题? 的确,带花

算法学习笔记 递归之 快速幂、斐波那契矩阵加速

递归的定义 原文地址为:http://blog.csdn.net/thisinnocence 递归和迭代是编程中最为常用的基本技巧,而且递归常常比迭代更为简洁和强大.它的定义就是:直接或间接调用自身.经典问题有:幂运算.阶乘.组合数.斐波那契数列.汉诺塔等.其算法思想: 原问题可分解子问题(必要条件): 原与分解后的子问题相似(递归方程): 分解次数有限(子问题有穷): 最终问题可直接解决(递归边界): 对于递归的应用与优化,直接递归时要预估时空复杂度,以免出现用时过长或者栈溢出.优化递归就是以