题解 UVA1617 【笔记本 Laptop】

传送门

分析

首先,我们发现每个 rir_idid_i 都是绑在一起的,于是就可以想到用 struct 结构体来存储每个区间的左右端点。

struct asdf
{
	int r,d;
}a[N];

既然要让空隙尽可能少,那么就意味着我们要尽量连接每个线段,也就是贪心,我们可以从左到右依次试着连接,为了能更好地连接右一个线段,我们得把当前放的线段尽量往右放,第一次放的线段放那个区间最右边,所以我们把这些区间按右端点从左到右排序,如果右端点一样,就按左端点从左到右排序。

bool cmp(asdf x,asdf y)
{
	return x.d<y.d||(x.d==y.d&&x.r<y.r);
	//按 右端点从左到右 或 右端点相等且左端点从左到右 排序 
}

我们用 RR 记录之前最靠右的线段的位置,一开始 R=a1.dR=a_1.d,即第一个区间的右端点。

接下来循环,从 2n2-n 开始尝试连接,我们会遇到 22 种情况:

第一种:R<ai.rR<a_i.r,此时不管线段怎么放,都无法与 RR 连接,所以只能放弃连接,增加空隙数,并把当前的线段放在 ai.da_i.d,并更新 RR,即 ans++;R=a[i].d

第一种

第二种:Rai.rR≥a_i.r,此时为就可以连接,为了让 RR 尽量靠右,我们只需把线段放在 RR 右侧,并更新 RR,即 R++;,不过,有种情况需要特判,若此时 RR 正好等于 ai.da_i.d,那么就不能放右边,我们可以选择放左边,所以需要特判一下。

第二种

几个小误区

1.1. 不可能出现 R>ai.dR>a_i.d 的情况,因为我们已经将右端点排序,上次选的 RR 一定是 Rai1.dai.dR≤a_{i-1}.d≤a_i.d

2.2. 题目中说“rirjr_i≤r_j,当且仅当 didjd_i≤d_j”,这意味着左端点较左的右端点也较左,也就是说不包含以下这种情况:

意外

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int T,n,ans,R;
struct asdf
{
	int r,d;
}a[N];
bool cmp(asdf x,asdf y)
{
	return x.d<y.d||(x.d==y.d&&x.r<y.r);
	//按 右端点从小到大 或 右端点相等且左端点从小到大 排序 
}
int main()
{
    cin>>T;
    while(T--)
    {
    	cin>>n;
    	for(int i=1;i<=n;i++)
    	{
    		cin>>a[i].r>>a[i].d;
		}
		sort(a+1,a+n+1,cmp);
    	ans=0;
    	R=a[1].d;//第一次取第一个区间右端点
		for(int i=2;i<=n;i++)
		{
			if(R<a[i].r)//第一种 
			{
				ans++;
				R=a[i].d;
			}
			else if(R!=a[i].d)//第二种  别忘了排除R==a[i].d 
			{
				R++;
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}
posted @ 2021-02-24 22:21  luckydrawbox  阅读(10)  评论(0)    收藏  举报  来源