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

本文解析了一道关于最大数量邀请徒步者的算法题,通过贪心策略和优先队列实现最优解,给出了详细的代码实现及思路说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

Hiking

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1681    Accepted Submission(s): 863
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 (1n105), the number of soda. The second line constains n integers l1,l2,,ln. The third line constains n integers r1,r2,,rn(0lirin)
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
 


思路:

       贪心的策略很容易想到,在所有满足条件的soda里,优先选择r小的那个。所以,要按照 l 对所有的soda进行排序,然后将 l 符合条件的soda放进优先队列,这个优先队列是按照 r 排序的,然后再优先队列中邀请每个soda。

代码:

#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <vector>
#include <iomanip>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
#define mod 1000000007
#define mem(a) memset(a,0,sizeof(a))

using namespace std;
const int maxn = 100000 + 5 , inf = 0x3f3f3f;

struct node{
    int l,r,p;
    //重载<运算符 用于优先队列的排序
    bool operator < (const node & a)const {
        return r > a.r ;
    }
};
node sodas[maxn];
vector<int>pos;//储存每次邀请的位置
//用于sort的排序
bool cmp(const node & a , const node & b ){
    if(b.l==a.l) return a.r<b.r;
    return a.l < b.l ;
}

int main(){
    int kase;
    scanf("%d",&kase);
    while(kase--){
        int n,cnt = 0;
        pos.clear();
        priority_queue<node,vector<node> >q;
        scanf("%d",&n);
        for(int i = 0 ; i < n ; i ++ ) scanf("%d",&sodas[i].l);
        for(int i = 0 ; i < n ; i ++ ) scanf("%d",&sodas[i].r);
        for(int i = 0 ; i < n ; i ++ ) sodas[i].p = i + 1;
        sort(sodas,sodas+n,cmp);//对soda按照 l 进行排序
        int i = 0;
        while(1){
            //i不断右移 找到符合条件的soda放入优先队列
            for(; i < n ; i ++ ){
                if(sodas[i].l<=cnt){
                    q.push(sodas[i]);
                }
                else break;
            }
            //对于补符合条件的soda 邀请了他们 但是他们并没有接受
            //直到找到一个符合条件的soda
            while(!q.empty()&&q.top().r<cnt){
                pos.push_back(q.top().p);
                q.pop();
            }
            //如果队列中没有符合条件的soda 退出
            if(q.size()==0) break;
            //如果有 就邀请他
            else{
                cnt++;
                pos.push_back(q.top().p);
                q.pop();
            }
        }
        //如何 i 没有到达 n 说明从 i 到 n-1 的soda都不符合条件 但是还需要邀请他们
        while(i<n){
            pos.push_back(sodas[i].p);
            i++;
        }
        //output
        printf("%d\n",cnt);
        for(int j = 0 ; j < pos.size() ; j ++ ){
            if(j) printf(" ");
            printf("%d",pos[j]);
        }
        printf("\n");
    }
}


转载于:https://www.cnblogs.com/seven7777777/p/10278743.html

内容概要:该PPT详细介绍了企业架构设计的方法论,涵盖业务架构、数据架构、应用架构和技术架构四大核心模块。首先分析了企业架构现状,包括业务、数据、应用和技术四大架构的内容和关系,明确了企业架构设计的重要性。接着,阐述了新版企业架构总体框架(CSG-EAF 2.0)的形成过程,强调其融合了传统架构设计(TOGAF)和领域驱动设计(DDD)的优势,以适应数字化转型需求。业务架构部分通过梳理企业级和专业级价值流,细化业务能力、流程和对象,确保业务战略的有效落地。数据架构部分则遵循五大原则,确保数据的准确、一致和高效使用。应用架构方面,提出了分层解耦和服务化的设计原则,以提高灵活性和响应速度。最后,技术架构部分围绕技术框架、组件、平台和部署节点进行了详细设计,确保技术架构的稳定性和扩展性。 适合人群:适用于具有一定企业架构设计经验的IT架构师、项目经理和业务分析师,特别是那些希望深入了解如何将企业架构设计与数字化转型相结合的专业人士。 使用场景及目标:①帮助企业和组织梳理业务流程,优化业务能力,实现战略目标;②指导数据管理和应用开发,确保数据的一致性和应用的高效性;③为技术选型和系统部署提供科学依据,确保技术架构的稳定性和扩展性。 阅读建议:此资源内容详尽,涵盖企业架构设计的各个方面。建议读者在学习过程中,结合实际案例进行理解和实践,重点关注各架构模块之间的关联和协同,以便更好地应用于实际工作中。
对于HDU4546问题,还可以使用优先队列(Priority Queue)来解决。以下是使用优先队列的解法思路: 1. 首先,将数组a进行排序,以便后续处理。 2. 创建一个优先队列(最小堆),用于存储组合之和的候选值。 3. 初始化优先队列,将初始情况(即前0个数的组合之和)加入队列。 4. 开始从1到n遍历数组a的元素,对于每个元素a[i],将当前队列中的所有候选值取出,分别加上a[i],然后再将加和的结果作为新的候选值加入队列。 5. 重复步骤4直到遍历完所有元素。 6. 当队列的大小超过k时,将队列中的最小值弹出。 7. 最后,队列中的所有候选值之和即为前k小的组合之和。 以下是使用优先队列解决HDU4546问题的代码示例: ```cpp #include <iostream> #include <vector> #include <queue> #include <functional> using namespace std; int main() { int n, k; cin >> n >> k; vector<int> a(n); for (int i = 0; i < n; i++) { cin >> a[i]; } sort(a.begin(), a.end()); // 对数组a进行排序 priority_queue<long long, vector<long long>, greater<long long>> pq; // 最小堆 pq.push(0); // 初始情况,前0个数的组合之和为0 for (int i = 0; i < n; i++) { long long num = pq.top(); // 取出当前队列中的最小值 pq.pop(); for (int j = i + 1; j <= n; j++) { pq.push(num + a[i]); // 将所有加和结果作为新的候选值加入队列 num += a[i]; } if (pq.size() > k) { pq.pop(); // 当队列大小超过k时,弹出最小值 } } long long sum = 0; while (!pq.empty()) { sum += pq.top(); // 求队列中所有候选值之和 pq.pop(); } cout << sum << endl; return 0; } ``` 使用优先队列的方法可以有效地找到前k小的组合之和,时间复杂度为O(nklog(k))。希望这个解法对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值