题目描述:一家餐厅收到了n份订单,每份订单有开始和结束时间,餐厅可以选择接或不接,接受的订单时间必须互不重合,即任意一刻都不能被两个订单占用。问餐厅最多能接受几份订单。
啊这,乍看是经典DP,但是不能直接写,需要多思考。以订单结束顺序排序。
f[i]表示处理订单数为i时,所用的最小时间,发现f[i]有单调性。
每次对一个订单,用开始时间二分查找f[k]<lef<=f[k+1],更新f[k+1]=min(f[k+1],rig)
最后f[]数组最后不为INF的对应下标就是答案。
#include<bits/stdc++.h>
//#define ll long long
using namespace std;
unordered_map<int,int> Mp;
int n;
struct Order
{
int lef,rig;
}a[500010];
int b[1000010];
int f[1000010],cnt=1;
bool my(Order a,Order b)
{
if(a.rig!=b.rig)return a.rig<b.rig;
else return a.lef<b.lef;
}
void Reunion()
{
int k=0;
sort(b+1,b+1+2*n);
for(int i=1;i<=2*n;++i)
{
if(b[i]!=b[i-1]) Mp[b[i]]=++k;
}
sort(a+1,a+1+n,my);
}
int Find(int x)
{
int lef=0,rig=cnt,mid;
//if(lef==rig) return 1;
while(lef+1<rig)
{
mid=(lef+rig)>>1;
if(f[mid]>x) rig=mid;
else lef=mid;
}
if(x>f[rig]) return rig;
else return lef;
}
int main()
{
cin>>n;
for(int i=1;i<=n;++i)
{
cin>>a[i].lef>>a[i].rig;
b[2*i-1]=a[i].lef,b[2*i]=a[i].rig;
}
Reunion();
int x,y,z;
f[1]=Mp[a[1].rig];
for(int i=2;i<=n;++i)
{
x=Mp[a[i].lef];
y=Mp[a[i].rig];
//cout<<Find(x)<<endl;
z=Find(x)+1;
//cout<<z<<endl;
//cout<<i<<' '<<x<<' '<<y<<endl;
//Alt(y,z);
if(!f[z]) f[z]=y;
else f[z]=min(f[z],y);
for(int j=cnt;;++j)
{
if(!f[j])
{
cnt=j-1;
break;
}
}
//for(int i=1;i<=cnt;++i)cout<<f[i]<<' ';cout<<endl;
//cout<<"gnerk"<<endl;
}
cout<<cnt<<endl;
//system("pause");
return 0;
}


京公网安备 11010502036488号