HDU 5360——Hiking——————【贪心+优先队列】

Hiking

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 118    Accepted Submission(s): 69
Special Judge

Problem Description

There are n soda conveniently labeled by 1,2,…,n. beta, their best friends, wants to invite some soda to go hiking. The i-th soda will go hiking if the total number of soda that go hiking except him is no less than li and no larger than ri. beta will follow the rules below to invite soda one by one:
1. he selects a soda not invited before;
2. he tells soda the number of soda who agree to go hiking by now;
3. soda will agree or disagree according to the number he hears.

Note: beta will always tell the truth and soda will agree if and only if the number he hears is no less than li and no larger than ri, otherwise he will disagree. Once soda agrees to go hiking he will not regret even if the final total number fails to meet some soda‘s will.

Help beta design an invitation order that the number of soda who agree to go hiking is maximum.

Input

There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:

The first contains an integer n (1≤n≤105), the number of soda. The second line constains n integers l1,l2,…,ln. The third line constains n integers r1,r2,…,rn. (0≤li≤ri≤n)
It is guaranteed that the total number of soda in the input doesn‘t exceed 1000000. The number of test cases in the input doesn‘t exceed 600.

Output

For each test case, output the maximum number of soda. Then in the second line output a permutation of 1,2,…,n denoting the invitation order. If there are multiple solutions, print any of them.

Sample Input

4

8

4 1 3 2 2 1 0 3

5 3 6 4 2 1 7 6

8

3 3 2 0 5 0 3 6

4 5 2 7 7 6 7 6

8

2 2 3 3 3 0 0 2

7 4 3 6 3 2 2 5

8

5 6 5 3 3 1 2 4

6 7 7 6 5 4 3 5

Sample Output

7

1 7 6 5 2 4 3 8

8

4 6 3 1 2 5 8 7

7

3 6 7 1 5 2 8 4

0

1 2 3 4 5 6 7 8

题目大意:Bate想邀请sodas出去玩。每个sodai有一个要求,即当前已经邀请到的人数必须在[l,r]之间。问按照什么顺序邀请sodas能使最后邀请到的人最多。

解题思路:首先按照l从小到大排,如果l相同,按照r从小到大排。然后用优先队列保存所有l值小于等于当前人数kt的soda。优先队列是让r按照小的优先。每次从队列中取出soda,判断是否r值大于等于当前人数kt。如果是,则让kt加1,放入ans数组。如果不是,则放入b数组。如果队列中没有元素的r值大于等于当前人数kt,则说明出现中断,以后的所有soda都放入b数组。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+20;
const int INF=0x3f3f3f3f;
struct Soda{
    int l,r,len,ord;
    bool operator < (const Soda &b)const {
        return r>b.r;
    }
}sodas[maxn];
priority_queue<Soda>PQ;
int ans[maxn],vis[maxn],b[maxn];    //b数组是没有去的soda编号,ans数组是去了
bool cmp(Soda a,Soda b){
    if(a.l!=b.l){
        return a.l<b.l;
    }else{
        return a.len<b.len;
    }
}
int main(){
    int t,n;
    scanf("%d",&t);
    while(t--){
        memset(vis,0,sizeof(vis));
        scanf("%d",&n);
        int flag=0;
        for(int i=0;i<n;i++){
            scanf("%d",&sodas[i].l);
            if(sodas[i].l==0){
                flag=1;
            }
        }
        for(int i=0;i<n;i++){
            scanf("%d",&sodas[i].r);
            sodas[i].ord=i+1;
            sodas[i].len=sodas[i].r-sodas[i].l+1;
        }
        if(!flag){
            printf("0\n",n);
            printf("1");
            for(int i=2;i<=n;i++){
                printf(" %d",i);
            }printf("\n");
            continue;
        }
        sort(sodas,sodas+n,cmp);
        int sum=0,kk=0,kt=0,nn=0;
        int fg=0;Soda tmp;
        for(int i=0;i<n;i++){
            if(!fg){
                if(sodas[i].l<=kt){
                    PQ.push(sodas[i]);
                }else{
                    i--;
                    int mark=0;
                    while(!PQ.empty()){
                        tmp=PQ.top();
                        PQ.pop();
                        if(tmp.r>=kt){
                            mark=1;
                            kt++;
                            ans[kk++]=tmp.ord;
                            break;
                        }else{
                            b[nn++]=tmp.ord;
                        }
                    }
                    if(mark==0&&PQ.empty())
                        fg=1;
                }
            }else{
                b[nn++]=sodas[i].ord;
            }
        }
        while(!PQ.empty()){
            tmp=PQ.top();
            PQ.pop();
            if(tmp.r>=kt){
                kt++;
                ans[kk++]=tmp.ord;
            }else{
                b[nn++]=tmp.ord;
            }
        }
        printf("%d\n",kt);
        printf("%d",ans[0]);
        ans[0]=0;
        for(int i=1;i<kk;i++){
            printf(" %d",ans[i]);
            ans[i]=0;
        }
        for(int i=0;i<nn;i++){
            printf(" %d",b[i]);
            b[i]=0;
        }printf("\n");
    }
    return 0;
}

  

时间: 2024-10-11 08:35:51

HDU 5360——Hiking——————【贪心+优先队列】的相关文章

HDU 5360 Hiking(优先队列)

Hiking Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 492    Accepted Submission(s): 263 Special Judge Problem Description There are  soda conveniently labeled by . beta, their best friends,

HDU 5360 Hiking (贪心+优先队列)

本文纯属原创,转载注明出处:http://blog.csdn.net/zip_fan.谢谢. 传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5360 Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Special Judge Problem Description There are n soda conveniently la

hdu 5360 Hiking(优先队列+贪心)

题目:http://acm.hdu.edu.cn/showproblem.php? pid=5360 题意:beta有n个朋友,beta要邀请他的朋友go hiking,已知每一个朋友的理想人数[L,R](现有L~R个人准备去,那么这个朋友就去). 求最多有多少人去. 及beta邀请朋友的顺序. 分析:每次邀请人的最优解就是:选会去的人里面R最小的那个人. 代码实现的话,cur代表已经准备go hiking的人数,每次将全部L<=cur的人放进优先队列,选出R最小的那个. 假设队列为空,那么剩下

HDU 5360 (贪心)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5360 题意:告诉你n个区间[ l[i],r[i] ],然后让你排序,必须左区间不大于它前边的总区间个数,右区间不小于前边的总区间个数,求该序列的最大长度以及序列: PS:场上做的时候,三个人三个思路,不知道为啥交流不力,就这么放过了这道题目: 我的思路:把每个区间当成一个新的区间,就是第i个区间,能做该序列的第几个区间,这样又是一个区间.比如,(0,2)可以做第1,2,3个区间,即1~3: 但是等我

HDU 5360 Hiking(线段树)

题意: n个人接受邀请的条件是已经接受邀请的人数区间在l[i] , r[i] 问怎样设置邀请顺序能使得接受邀请的人数最多 解析: 先对区间从小按照右边界从小到大排序,如果右边界相同,再按照左边界从小到大排序.因为右边界越小优先级越高,左边界同理. 如果用优先队列,是算出选择当前人选择哪个区间是最优的. 由于本人不会两个条件的优先队列,所以只能换了一种写法来写. 于是我想到了线段树,逆向思维,利用线段树来维护这个区间选择哪个人是最优的. 选择完这个人之后,将这个人置为无穷大并维护线段树. 并记录下

HDU 6301 (贪心+优先队列)

题目大意: 求一个长度为n的数列, 给出m个区间,这m个区间各自区间内的数不同 题解: 用优先队列来模拟过程 , 解题思路是想到了 , 可是不知道如何实现 , 果然还须继续努力呀 这道题思路是去掉重复的区间(取最大的区间,用sort+结构体加几个判断条件来实现),用优先队列维护1-n 中没有出现的数(比如给你一个10 3 [2  8]  [1  5]  [6  10]  的样例,把1 到 10 push进优先队列后,排序后[1  5]  这个区间先,所以先从优先队列里取 1 2 3 4 5,此时

hdu 5360 Hiking

#include<stdio.h> #include<string.h> #include<queue> #include<algorithm> using namespace std; const int N=100000+5; struct node { int st,ed,id; friend bool operator < (node n1,node n2) { return n2.ed<n1.ed; } }p[N]; priority_

HDU 5360(2015多校6)-Hiking(优先队列)

题目地址:HDU 5360 题意:给定n个人,现在要邀请这些人去远足,但每个人同意邀请的条件是当前已经同意去远足的人数c必须满足c>=l[i]&&c<=ri,问你邀请的顺序是什么才能使尽可能多的人去远足,若有多个最优解,输出任意的一个. 思路:先按照L从小到到排序,把当前符合的L放入优先队列中 ,然后对队列中的R从小到大排序,贪心的选择R小的,然后乱搞一番就可以了. #include <stdio.h> #include <math.h> #includ

hdu 2850 Load Balancing (优先队列 + 贪心)

题目大意: 怎么分配n个任务到m个服务器上使得负载尽量平衡. 思路: 将任务从大到小排序,依次放入负载最小的那个服务器中. 因为是spj 的缘故,所以可以使用这个贪心. 比如数据 6 2 7 5 3 3 3 3 就会得到错误答案. #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <queue> using namespac