Cleaning Shifts POJ - 2376(反贪?)

FJ分配 N (1 <= N <= 25,000) 只中的一些奶牛在牛棚附近做些清洁。 他总是要让至少一只牛做清洁。他把一天分成T段(1 <= T <= 1,000,000), 第一段是1,最后一段是T

每只奶牛只在一些时间段有空。奶牛如果选择某一段时间,则必须完成整段时间的工作

你的任务是帮助FJ安排一些奶牛,使每段时间至少有一只奶牛被安排来做这件事。并且奶牛数应尽可能小。如果不可能办到,输出-1

输入

注意,输入包含多组测试数据,请处理到文件结束
* 第一行:N和T
* 第二行至N+1行: 每一行包括奶牛能工作的开始和结束时间。闭区间。

输出

*每组数据一行,输出完成清洁所需最少的奶牛数,如果不可能办到,输出-1

样例输入

3 10
1 7
3 6
6 10

样例输出

2

提示

这道题输入数据很多,请用scanf而不是cin

输入说明

这里有3只奶牛和10个时间段cow #1 能在时间段1..7工作, cow #2 能在时间段3..6工作, cow #3 能在时间段6..10工作

输出说明:

选择 cows #1 和 #3即可,没有更优的方案了 .

看到这个题目,感觉怎么不像贪心呢?贪心不是越贪越多吗?于是我这个大一弱菜没有了思路,看了看大神的代码,解法真是太妙了,也是一个贪心策略的选择,思想总是好想,但是代码实现(对我来说有些困难),虽然是反着贪心,但还是要贪心的呀。下面我来说说这个题目的贪法。

#include <iostream>
#include <algorithm>
#include <string>
#include <ctime>
#include <cmath>
#include <queue>
#include <vector>
#include <set>
#include <cstring>
#define MAXN 25100
using namespace std;
struct Node
{
    int start_time;
    int end_time;
};
bool cmp(const Node &x1, const Node &x2)
{
    if(x1.start_time == x2.start_time)
        return x1.end_time > x2.end_time;
    return x1.start_time < x2.start_time;
}
int main()
{
    int n, T;
    Node cow[MAXN];
    while(cin >> n >> T)
	{
        for(int i = 0; i < n; ++i)
            cin >> cow[i].start_time >> cow[i].end_time;
        sort(cow, cow + n, cmp);
        int time = 0;
        int ans = 0;
        int last_time = 0;
        bool flag = false;
        for(int i = 0; i < n; ++i)
		{
            bool xx = false;
            while(cow[i].start_time <= last_time + 1)
			{
                xx = true;
                time = max(time, cow[i].end_time);
                i++;
            }
            last_time = time;
            ans++;
            if(xx)
               i--;
            if(last_time >= T)
			{
                flag = true;
                break;
            }
        }
        if(flag)
        	cout << ans << endl;
        else
        	cout << -1 << endl;
    }
    return 0;
}

首先这类区间问题都要有一个贪心的策略,就像那些时间段的活动(要求是贪的越多)我们就可以按照结束时间的先后顺序来看每一个活动时间段的起始时间,就可以找出最多的活动安排。这道题目是用最少牛来使所有的时间段内都有牛在值班,我们也可以这样想,肯定是先让牛(最先开始值班的,最好就是一开始就可以值班的),如果开始时间一样,然后再把那个值班时间长的先排在前面(因为要数量最小的牛,一个值班时间长的可能顶好几个偷懒的牛)。这样就是这个贪心策略。接下来看看这个代码实现:

首先题目有一个限制条件,就是必须所有的时间段都得有牛,这就要求我们将时间段都得连起来,就是下面这个代码,

 while(cow[i].start_time <= last_time + 1)
	{
                xx = true;
                time = max(time, cow[i].end_time);
                i++;
         }
    last_time = time;
    ans++;

(先假设所有的时间段都有牛值班)如果有很多的小时间段和一个长时间段,我们就直接上长时间段的牛,这个 while 循环就会直接跳过这些小时间段的,找到下一个时间段(这个长时间段牛该下班了)该上班的牛,找到下一个时间段的牛后(就是不在这个前一个牛工作时间内的牛),每次都会更新这个time为新的这个牛的下班时间(毕竟要往后遍历),在这时候将要安排的牛数量+1。

             if(xx)
               i--;
            if(last_time >= T)
	    {
                flag = true;
                break;
            }

下面看看这个操作怎么判断出不可能办到的,<=lasttime+1就判断是否可以连起来,比如1--5  ,6--7就可以连起来,而7--8 就连不起来。只要这次连不起来(time 就不会更新,就会断在这里),下一次的数据(起始时间)就会更大,永远也不会更新这个time,lasttime 也不会变化,last_time >= T 这条语句就不会满足,flag 就是 false,当退出循环时,就输出-1,如果可以连起来并且到达总时间处,就会输出最小的牛。

说了好多。   

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值