zoukankan      html  css  js  c++  java
  • [转]会场安排问题 南阳理工学院OJ 题目14

    题目链接: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;
    }
  • 相关阅读:
    char和QChar(Unicode的编码与内存里的值还不是一回事)
    ddd
    vim实用笔记
    设计思想
    await使用中的阻塞和并发
    单元测试
    C#简单实现贪吃蛇程序(LinQ + Entity)
    JS逗号、冒号与括号
    C#实现对文件目录的实时监控
    在线预览PDF
  • 原文地址:https://www.cnblogs.com/yinger/p/2043022.html
Copyright © 2011-2022 走看看