题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=14
经典问题。此题的最佳解法是用贪心算法:
1) 将所有输入活动按照结束时间从早到晚排序
2) 顺序遍历列表,将可以加入日程的活动加入,并维护活动计数
3) 遍历完毕后,输出活动计数
整个过程需要1) 将活动列表排序O(nlogn) 2) 遍历列表O(n),因此复杂度为O(nlogn)
#include < iostream >
#include < vector >
#include < utility >
#include < algorithm >
using namespace std;
bool Comp( const pair < int , int > A1, const pair < int , int > A2)
{
return A1.second < A2.second;
}
void greedySelect()
{
int start,finish;
int m;
cin >> m;
while (m -- ){
int n;
cin >> n;
vector < pair < int , int > > Avec;
vector < pair < int , int > > Svec;
while (n -- )
{
cin >> start >> finish;
Avec.push_back(make_pair(start,finish));
}
cin.clear();
sort(Avec.begin(),Avec.end(),Comp);
vector < pair < int , int > > ::iterator iter = Avec.begin();
Svec.push_back(make_pair(iter -> first,iter -> second));
finish = iter -> second;
for ( ++ iter;iter != Avec.end(); ++ iter)
if (iter -> first > finish)
{
Svec.push_back(make_pair(iter -> first,iter -> second));
finish = iter -> second;
}
cout << Svec.size() << endl;
}
}
int main()
{
greedySelect();
return 0 ;
}
以下是我ac的解法,没有标准解法优,在此只是存下来留个念想,其他人可以直接忽略。
我的思路是:
1. 递归穷举(这个解法TLE,没什么价值,忽略)
2. 贪心(基于起始时间排序)
1) 对活动按照开始时间排序
2) 消去不可能活动(肯定安排不到的活动)
不可能活动的定义:在所有n个活动ai(i=1, 2 ... n)组成的集合S中,对于任意的ai∈S,若存在aj∈S(i≠j),使得b(aj)≤b(ai), e(aj)≥e(ai)(b,e代表开始时间/结束时间),则aj一定不在使得活动数最多的活动集合中,可以将其从S中删去。活动aj即为不可能活动。
举个例子,以下几个活动集(一行为一个集合)中,只有红字的活动需要考虑,其它都可以删除。
{3,4} {2,4} {1,4} {1,5}
{2,3} {1,3} {2,4} {2,3}
删除不可能活动最简单的方法就是二层嵌套循环,复杂度为O(n^2),为了降低复杂度,可以在第1) 步的排序上做一些工作。
例如可以对活动按照(b↑e↓) 进行排序,这样可以使得在初始的几重循环中删去尽量多的元素,从而降低一些时间复杂度。
3) 按照贪心方法安排活动
遍历列表,将所有能够加入的活动加入。遍历完毕后,输出活动计数。
算法需要一次排序(O(nlogn)),一次嵌套循环(O(n^2)),因此复杂度为O(n^2)
标准解法和我的贪心解法都可以得到ac,不过标准解法在时间上明显优于我的解法。
标准解法:时间260内存308
我的解法:时间800内存308
#include < iostream >
#include < vector >
#include < algorithm >
using namespace std;
typedef struct _AR{
int b;
int e;
}AR;
bool operator < ( const AR & a, const AR & b){
if (a.b == b.b) return a.e > b.e;
return a.b < b.b;
}
vector < AR > arv;
template < class T >
void reverse(vector < T > & v){
T temp;
for ( int i = 0 ; i < v.size() / 2 ; i ++ ){
temp = v[i];
v[i] = v[v.size() - i - 1 ];
v[v.size() - i - 1 ] = temp;
}
}
void reduce(vector < AR > & v){
reverse(v);
vector < AR > ::iterator it = v.begin();
vector < AR > ::iterator it2;
while (it != v.end()){
it2 = it;
it2 ++ ;
while (it2 != v.end()){
if (it2 -> e >= it -> e){
v.erase(it2);
}
else {
it2 ++ ;
}
}
it ++ ;
}
reverse(v);
}
int main()
{
int n;
cin >> n;
while (n -- ){
arv.clear();
int c;
cin >> c;
while (c -- ){
int b, e;
cin >> b >> e;
AR a;
a.b = b;
a.e = e;
arv.push_back(a);
}
sort(arv.begin(), arv.end());
reduce(arv);
int r = - 1 ;
int count = 0 ;
for (vector < AR > ::iterator it = arv.begin(); it != arv.end(); it ++ ){
if (it -> b > r){
r = it -> e;
count ++ ;
}
}
cout << count << endl;
}
return 0 ;
}