《算法竞赛进阶指南》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]); }
标签:头牛,int,0x07,pair,ans,POJ3190,畜栏,include,进阶 来源: https://www.cnblogs.com/randy-lo/p/13139099.html