- 题意
题意:给出n段区间和区间长度T(从1开始),以下n行为每段区间的首位地址,求最少需要几段将所有区间覆盖,如果不能全覆盖就输出-1. - 思路
这道题要先注意能不能完全覆盖,如果n段区间打头的没有1,那就直接输出-1.如果计算结尾不是T也是输出-1.
还有一个要考虑的,容易曲解题意的一点,选取的区间只要完全覆盖就行,但不要求每一段都重叠,假如总长度为7,可以由1~3和4~7来组成。
然后考虑解决方法,想用尽可能少的区间,如何去选取,假设给一个例子,长度为20,有7段,分别是
(1,5),(2,6),(3,10),(4,9),(6,15),(10,18),(17,20)
先从区间能否完全覆盖考虑,从1开始,有20结束,符合。
再从最左端考虑,头是1,尾是5,在1~5区间内包含(2,6),(3,10),(4,9)这三个区间的一部分,另外还有(6,15)这个区间可以和1~5区间进行连接,那我们这一步可以考虑的区间就有这4个了。那选哪一个最合适?x显然是6~15,因为这个区间最右边是15,最靠近终点。这就是贪心的方向。接下来重复上一次步骤,看看(6~)15以内都有哪些区间:只有(10,18)接壤,所以这一次选到18。下一次选17~20,结束。
由于我给的例子是排好序的,但是给的数据是无序的,所以需要自己排好序,按照起始位置从小到大,如果起始位置一样就按照结束位置排。 - 代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
using namespace std;
struct A
{
int tou;
int wei;
};
A a[30000];
int T,n;
int cmp(A a,A b)
{
if(a.tou != b.tou)
return a.tou < b.tou;
else
return a.wei > b.wei;
}
void input()
{
for(int i = 0 ; i < n ; i++)
cin>>a[i].tou>>a[i].wei;
}
void solve()
{
sort(a,a+n,cmp);
int i = 0,r = 0,t = 0,ans = 1;
r = a[i].wei;
t = r;
if(a[i++].tou != 1) cout<<-1<<endl;
else
{
for( ; i < n && r != T ; ans++ )
{
bool no_higher = true;
while( i < n && a[i].tou <= r + 1 )
{
if( a[i].wei > t )
t = a[i].wei,no_higher = false;
i++;
if(t == T) break;
}
if( no_higher )
break;
else
r = t;
}
if(r == T) cout<<ans<<endl;
else cout<<-1<<endl;
}
}
int main()
{
#ifdef H_R
freopen("in.txt","r",stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(false);
while(cin>>n>>T)
{
input();
solve();
}
return 0;
}