最大重叠事件数的持续时间

Duration of maximum number of overlapping events

在尝试提高我的算法技能时,我发现自己陷入了以下问题,简而言之,它要求您找出房间中出现最大人数的时间跨度的持续时间:

https://jutge.org/problems/P27158_en

我想出的解决方案正确解决了网站建议的所有 public 个测试用例的问题,但它无法解决一个或多个隐藏的私人测试用例。

我的解决方案在 std::vector 中为每个事件保存两个条目:一个用于到达,一个用于离开,每个条目由 [eventtype, eventtime] 组成。然后按事件时间对向量进行排序,最后循环遍历向量以确定存在最大客人数的时间跨度的持续时间。我的代码如下:

            #include <iostream>
    #include <vector>
    #include <algorithm>

    using namespace std;

    enum class EventType {ARRIVE, LEAVE};

    struct Event{
        int time;
        EventType type;

        Event(){}
        Event(int tm, EventType t) : time(tm), type (t){}
       // inline bool operator<(const Event& e) const {return time < e.time || (time == e.time && type==EventType::LEAVE);}
    };

    bool eventCompare(const Event& e1, const Event& e2) {
        if(e1.time < e2.time){
            return true;
        } else if(e1.time == e2.time) {
            if(e1.type == EventType::LEAVE && e2.type == EventType::ARRIVE) {
                return true;
            } else  {
                return false;
            }
        } else {
            return false;
        }
    }

    int main()
    {
        int visits;
        int timeStart, timeEnd;
        int maxVisits, maxDuration, localMaxVisits, localStartTime, localEndTime, duration;
        std::vector<Event> events;
        std::vector<Event>::const_iterator it;
        // Get each Case from stdin.
        // 0 is the special stopping case.
        while(cin>>visits && visits!=0) {
            events.clear();
            // Read all the visits, for each one save two entries to the visits-vector,
            // one for the arrival time another for the leaving time.
            for(int i=1; i<=visits; ++i){
                cin>>timeStart>>timeEnd;
                Event eStart(timeStart, EventType::ARRIVE);
                Event eEnd(timeEnd, EventType::LEAVE);
                events.push_back(eStart);
                events.push_back(eEnd);
            }
            // Sorting the vector so that events are ordered by their arrival time.
            // In case two events coincide on arrival time, we place leaving events before arrival events.
            std::sort(events.begin(), events.end(), eventCompare);
            maxVisits=0;
            maxDuration=0;
            localMaxVisits=0;
            localStartTime=0;
            localEndTime=0;
            // Loop through the sorted vector
            for(it=events.begin(); it!=events.end(); ++it){
                // If the event type is arrival
                if((*it).type == EventType::ARRIVE) {
                    // We only reset the localStartTime if there is no
                    // gap between the last endtime and the current start time
                    // For example two events 11-13 and 13-15 should be treated as one long event
                    // with duration 11-15
                    if(localEndTime < (*it).time) {
                        localStartTime = (*it).time;
                    }
                    localMaxVisits++;
                } else { // Event type leave
                    // Calculate the duration
                    duration = (*it).time - localStartTime;
                    // If we have a new max in overlaps or equal overlaps but larger duration than previous
                    // We save as the global max.
                    if(localMaxVisits > maxVisits || (localMaxVisits == maxVisits && duration>maxDuration)) {
                        maxVisits=localMaxVisits;
                        maxDuration = duration;
                    }
                    localMaxVisits--;
                    localEndTime= (*it).time;
                }
            }
            cout<<maxVisits<<" "<<maxDuration<<endl;
        }
        return 0;
    }

我已经根据@j_random_hacker 的评论修改了代码,程序现在不会像以前对隐藏的私人测试用例那样超过时间限制,但现在得到一个判决 "Wrong answer"(仅适用于私有测试用例)。我会尝试找出算法错误可能是什么。感谢所有回答的人。

我将比较函数更改为此,TLE 消失了(并更改为 WA):

bool operator< ( const Event& e ) const
{
    return (time < e.time) || (time == e.time && type==EventType::LEAVE && e.type != EventType::LEAVE);
}

如评论中所述,原因是您提供的比较功能没有 strict weak ordering。 (即使两个对象具有相同的 time 和相同的 type(EventType::LEAVE),它也返回 true,而当两个对象相同时,它应该返回 false。 )

编辑:

您获得 WA 是因为像这样的测试用例:

5 1 3 1 3 3 4 4 7 4 7

你的输出 - 2 6
正确的输出 - 2 3

您得到的事件的最大数量是正确的,但它们的持续时间是错误的。

对此的补救方法是在两次迭代中计算答案。
在第一次迭代中,我们计算最大事件数。
在第二次迭代中,我们使用第一次迭代中获得的结果计算最大持续时间。

正确的代码(和你的差不多):

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

enum class EventType {ARRIVE, LEAVE};

struct Event
{
    int time;
    EventType type;

    Event() {}
    Event ( int tm, EventType t ) : time ( tm ), type ( t ) {}
    bool operator< ( const Event& e ) const
    {
        return ( time < e.time ) || ( time == e.time && type == EventType::LEAVE &&
                                      e.type != EventType::LEAVE );
    }
};

int main()
{
    int visits;
    int timeStart, timeEnd;
    int maxVisits, maxDuration, localMaxVisits, localStartTime, localEndTime,
         duration;
    std::vector<Event> events;
    std::vector<Event>::const_iterator it;
    // Get each Case from stdin.
    // 0 is the special stopping case.
    while ( cin >> visits && visits != 0 )
    {
        events.clear();
        // Read all the visits, for each one save two entries to the visits-vector,
        // one for the arrival time another for the leaving time.
        for ( int i = 1; i <= visits; ++i )
        {
            cin >> timeStart >> timeEnd;
            Event eStart ( timeStart, EventType::ARRIVE );
            Event eEnd ( timeEnd, EventType::LEAVE );
            events.push_back ( eStart );
            events.push_back ( eEnd );
        }

        // Sorting the vector so that events are ordered by their arrival time.
        // In case two events coincide on arrival time, we place leaving events before arrival events.
        std::sort ( events.begin(), events.end() );

        maxVisits = 0;
        localMaxVisits = 0;

        // Find `maxVisits`
        for ( it = events.begin(); it != events.end(); ++it )
        {
            if ( ( *it ).type == EventType::ARRIVE )
            {
                localMaxVisits++;
            }
            else
            {
                maxVisits = max ( maxVisits, localMaxVisits );
                localMaxVisits--;
            }
        }


        maxDuration = 0;
        localStartTime = 0;
        localEndTime = 0;

        // Now calculate `maxDuration`
        for ( it = events.begin(); it != events.end(); ++it )
        {
            if ( ( *it ).type == EventType::ARRIVE )
            {
                localMaxVisits++;
                if ( localMaxVisits == maxVisits && localEndTime < ( *it ).time )
                {
                    localStartTime = ( *it ).time;
                }
            }
            else
            {
                duration = ( *it ).time - localStartTime;
                if ( localMaxVisits == maxVisits )
                {
                    localEndTime = ( *it ).time;
                    maxDuration = max ( maxDuration, duration );
                }
                localMaxVisits--;
            }
        }

        cout << maxVisits << " " << maxDuration << endl;
    }
}

您可以通过完全取消 Event class 并使用 pair<int,int> 来简化您的代码。配对按第一个元素(即您的活动时间)排序,然后按第二个元素排序。我建议使用类似于以下的代码填充您的矢量:

    vector<pair<int,int>> v;
    for (int i=0; i<n; i++) { // n events to add
        int a, b;
        cin >> a >> b;            
        v.push_back({a, 1});  // 1 for "enter"
        v.push_back({b, -1}); // -1 for "leave"
    }
    sort(v.begin(), v.end());

如您所见,排序不需要定义任何额外的内容。它只是工作 (tm)。

两个陷阱:

  • 如果我在 t0 到达,而其他人在 t0 离开,则聚会人数没有改变。
  • 如果很多人同时到达或离开,你应该只重新计算一次帮助变化(如果是0,完全忽略它,就像前面的陷阱)。

我也可以确认,对于这个特定的问题,法官不会接受任何使用复杂结构的答案(我最初尝试用 map<int, int> 来解决它)。单纯表演

    map<int,int> m;
    for (int i=0; i<n; i++) { // n events to add
        int a, b;
        cin >> a >> b;            
        m[a]++;  // add 1 party-goer at time a
        m[b]--;  // remove 1 at time b
    }

让你超过时间限制(即使它会自动排序)。因此,即使区间树非常适合重复的区间查询,它们也不是解决这个特定问题(只查询一次)的正确工具。

祝你为那个难以捉摸的 AC 修复代码好运!我可以确认它 可以实现的。