多校第六场 1008 hdu 5360 Hiking(贪心+STL)

本文介绍了一种解决HDU5360问题的方法,该问题关注如何最大化接受邀请的人数。通过将人员按特定条件排序并使用优先队列进行贪心选择,文章详细解释了算法的设计思路及实现过程。

题目链接:

hdu 5360


题目大意:

有n个人,他们都会被邀请,但只有在已经接受邀请的人的数量在某个区间当中的时候,他才会选择接受邀请,问如何邀请才能保证最终接受邀请的人的数量最多。


题目分析:

  • 首先初始的人数sum=0,只有当 lisum 的时候第i个人被邀请才有可能答应,所以我们先对所有人按照 li 从小到大排序,正好是他们加入优先队列的。然后我们每次只要从可选的人(用优先队列维护)当中选择 ri 最小的,因为如果因为人数增长导致已经在优先队列当中的人不能被选,那么一定是 ri 最小的这个,所以贪心的选择它一定会得到最优解。
  • 那么如何优先队列中可以选取的元素。首先当当前的 sumli 那么可以将第i个人放入优先队列,表示已经可以被邀请,当 sumrtop 的时候,那么这个人已经不能被选了,所以应该出队,因为人已经排序,所以按顺序加入即可。
  • 算法的复杂度是 O(nlog2n)

AC代码:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
#include <vector>
#define MAX 100007

using namespace std;

struct Node
{
    int id,l,r;
}p[MAX];

bool cmp ( Node a, Node b )
{
    if ( a.l == b.l ) return a.r < b.r;
        return a.l < b.l;
}

struct Node1
{
    int id,r;
    Node1 ( int a , int b )
    {
        r = a;
        id = b;
    }
    bool operator < ( const Node1& a ) const
    {
        return r > a.r;
    }
};

int t,n;
vector<int> ans;
priority_queue<Node1> q;

int main ( )
{
    scanf ("%d" , &t );
    while ( t-- )
    {
        scanf ( "%d" , &n );
        for ( int i = 0 ; i < n ; i++ )
            scanf ( "%d" , &p[i].l);
        for ( int i = 0 ; i < n ; i++ )
            scanf ( "%d" , &p[i].r);
        for ( int i = 0 ; i < n ; i++ )
            p[i].id = i+1;
        sort ( p , p+n , cmp );
        while (!q.empty()) q.pop();
        ans.clear();
        int num = 0;
        int i = 0;
        while ( true )
        {
            //cout << i << " " << p[i].l << " " << p[i].r << " " << num <<" " << q.size()<< endl;
            while ( i < n && p[i].l <= num && p[i].r >= num )
            {
                q.push ( Node1 ( p[i].r , p[i].id ));
                i++;
            }
            if ( !q.empty() )
            {
                while ( !q.empty() && q.top().r < num )
                {
                    ans.push_back ( q.top().id );
                    q.pop();
                }
                if ( !q.empty() )
                {
                    ans.push_back ( q.top().id );
                    q.pop();
                    num++;
                }
            }
            if ( q.empty() && ( i >= n || p[i].l > num || p[i].r < num ) ) break;
        }
        for ( ;i < n ;i++ )
            ans.push_back ( p[i].id );
        printf ( "%d\n" , num );
        for ( int i = 0 ; i < ans.size() ; i++ )
        {
            if ( i ) printf ( " ");
            printf ( "%d" , ans[i] );
        }
        puts ( "");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值