[转]会场安排问题 南阳理工学院OJ 题目14
2011-05-11 11:25
246 查看
会场安排问题
题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=14
经典问题。此题的最佳解法是用贪心算法:
1) 将所有输入活动按照结束时间从早到晚排序
2) 顺序遍历列表,将可以加入日程的活动加入,并维护活动计数
3) 遍历完毕后,输出活动计数
整个过程需要1) 将活动列表排序O(nlogn) 2) 遍历列表O(n),因此复杂度为O(nlogn)
以下是我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
题目链接: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; }
相关文章推荐
- 南阳理工OJ_题目14 会场安排问题
- 题目14 会场安排问题
- 贪心——NYOJ 题目14 会场安排问题
- 会场安排问题--nyoj题目14
- 会场安排问题(南阳oj14)(贪心-区间不重叠)
- 【南阳OJ 14】 会场安排问题(贪心)
- NYOJ 14 会场安排问题(经典题目,贪心,区间问题)
- NYOJ 题目14 会场安排问题(贪心)
- 南阳题目14-会场安排问题
- NYOJ 题目14 会场安排问题
- NYOJ题目14会场安排问题(贪心)
- 南阳理工 oj14 会场安排问题
- nyoj 题目14:会场安排问题 贪心算法
- 题目14:会场安排问题
- nyoj14会场安排问题VS hdoj2037今年暑假不AC(贪心之时间安排问题)
- 会场安排问题---nyoj14
- NYoj 14会场安排问题
- NYOJ-14 会场安排问题
- NTOJ-14-会场安排问题(贪心算法)
- nyoj 14:会场安排问题