题目链接: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;
}