《算法竞赛进阶指南》0x07贪心 POJ3190

题目链接:http://poj.org/problem?id=3190

题目中给定N头牛的吃草开始时间和结束时间,每头牛必须单独在一个牛栏里吃草,问最少需要多少个牛栏能满足要求?

抽象出来的模型就是最少能将N个区间不相交地分布在多少个栏目中?

算法步骤:

将所有牛按开始吃草的时间排序;
用小根堆维护当前所有畜栏的最后一头牛的吃草结束时间;
如果当前的牛可以安排在堆顶的畜栏中,则将其安排进去,否则就新建一个畜栏;
证明:

反证法,假设存在一种方案,使得需要的畜栏数量更少,记其需要的畜栏数量是 m。

考虑在上述做法中,第一次新建第 m+1个畜栏的时刻,不妨设当前处理的是第 i 头牛。

由于所有牛是按开始时间从小到大排好序的,所以现在前 m个畜栏中最后一头牛的开始时间一定小于等于第 i 头牛的开始时间。

而且前 m 个畜栏中最小的结束时间大于等于第 i 头牛的开始时间,所以前 m 个畜栏里最后一头牛的吃草区间一定都包含第 i 头牛的开始时间,所以我们就找到了 m+1 个区间存在交集,所以至少需要 m+1个畜栏,矛盾。

所以上述做法可以得到最优解,证毕。

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue> 
using namespace std;
#define maxn  50010
#define P pair<int,int>
struct cow{
    int l,r;
    int ans,id;//记录输入编号以及最终放到哪个畜栏中 
    bool operator < (const cow& c) const{
        return l<c.l;//按照左端点进行排序 
    }
}a[maxn];
int n;
int ans[maxn];
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        a[i].id=i;
        scanf("%d%d",&a[i].l,&a[i].r);        
    }
    sort(a+1,a+n+1);
    priority_queue<P,vector<P>,greater<P> >q;//创建小根堆
    q.push(make_pair(a[1].r,1));
    a[1].ans=1;
    for(int i=2;i<=n;i++){
        int num=q.size();
        if(a[i].l>q.top().first){
            a[i].ans=q.top().second;
            q.pop();
            q.push(make_pair(a[i].r,a[i].ans));
        }else{
            a[i].ans=++num;
            q.push(make_pair(a[i].r,num));
        }
    }
    cout<<q.size()<<endl;
    for(int i=1;i<=n;i++)ans[a[i].id]=a[i].ans;
    for(int i=1;i<=n;i++)printf("%d\n",ans[i]);
}

 

posted @ 2020-06-16 08:57  WA自动机~  阅读(210)  评论(0编辑  收藏  举报