EOJ1488 COIN COLLECTOR 贪心

本文介绍了一种解决硬币找零问题的方法,通过贪心策略构造最优解,确保硬币收藏家获得尽可能多的新硬币类型,同时最小化找零所需的金额。

和舍友打了一个半小时嘴炮,终于搞定了这道题,很开心。本题思路就是构造一个答案a0,a1,a2......     ai是找零的硬币。而需要找零的总钱数就是a0+a1+a2......


贪心策略:


1.因为题目要求是获得最多种未曾获得的硬币,所以我们最开始的想法是将所有没获得的硬币都放进答案中。但是这样真的对吗?假如输入是1 0, 2 0, 3 0。那么找零为6时,1,2,3不会都用到。因为 1 + 2 >= 3,所以在经过3找零后,需要找零的钱<=2,所以1,2至多有一个数被用到。这启发我们假如已经构造了局部最优答案a,b。想要构造更大的答案a,b,c时。当a + b >= c,a,b,c三个数不可能同时用到。所以这个时候我们就要开始删除一个数了,咋删呢?看策略2。


2.假如删除c,因为a + b >= c所以在找零的时候必然会先被c找零,所以这种方法是错误的。那么我们就要从a,b中间删一个,根据题意要使得找零的钱数最少,所以我们删掉a,b中较大的那个b.


3.假如c硬币收藏家已经有了,从答案中删除c


hint:有人可能会想到这样一个问题,我们从答案a,b,c向a,b,c,d拓展时,假如a+b+c>=d,我们要删除c,那么会不会剩下的a+b仍然大于d呢?即我们要连续删除多个数直至前面的和小于后面。答案是否定的!!最多删除一个数。假如a+b+c>=d 且 a+b>=d。由于a,b,c是已经构造好的答案,所以还有a+b<c。我们得出c>a+b>=d,即c>d的荒谬结论,c面值肯定小于d,因为我们是按面值从小到大拓展的。


举个例子:输入是

7 25

1 0

2 0

3 1

5 0

10 0

13 0

20 0

先构造答案1 2

构造1 2 3

发现1 + 2 >= 3

删除2

又因为3已经有了

删除3

构造的答案就是1

再构造1 5

再构造1 5 10

因为1 + 5 < 10所以可用

再构造1 5 10 13

因为1 + 5 + 10 >= 13

所以删除10

因为13没有

所以答案是1 5 13

再构造 1 5 13 20

发现1 + 5 + 13 + 20 > k - 1超出限制

所以删掉20

即最后的答案就是 1 5 13

收藏家需要花的钱是k - (1 + 5 + 13) = 6

具体代码如下:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <sstream>
#include <fstream>
#include <istream>
#include <ostream>
#include <complex>
#include <cstring>
#include <utility>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <string>
#include <cctype>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <new>
#include <set>
#include <map>
 
using namespace std;
 
const int maxn = 500000 + 5;
const int INF = 0x3f3f3f3f;
typedef long long int LL;
typedef vector<LL> vec;
 
vec ans;//保存答案
 
int main()
{
    //freopen("1.txt", "r", stdin);
    LL n, k;
    scanf("%I64d%I64d", &n, &k);
    LL sum = 0;
    for (int i=0; i<n; i++)
    {
        LL p, has;
        scanf("%I64d%I64d", &p, &has);
        if (sum >= p)//要删去上次答案的最后一项
        {
            sum -= ans[ans.size() - 1];
            ans.pop_back();
        }
        if (!has)//如果当前硬币收藏家没有,则加入答案中
        {
            if (sum + p > k - 1)
                break;
            ans.push_back(p);
            sum += p;
        }
    }
    if (sum == 0)//如果硬币收藏家全有,则找零的钱为1
        sum = 1;
    cout << ans.size() << endl << k - sum << endl;
    return 0;
}


### 关于EOJ DNA排序问题的解题思路 在处理EOJ中的DNA排序问题时,主要挑战在于如何高效地完成字符串数组的排序以及去重操作。由于题目涉及两个测试点可能因时间复杂度较高而超时,因此需要优化算法设计。 #### 数据结构的选择 为了降低时间复杂度并提高效率,可以引入`std::map`或者`unordered_map`来辅助实现去重功能[^1]。这些数据结构能够快速判断某项是否存在集合中,并支持高效的插入和查找操作。具体来说: - 使用 `std::set` 可以自动去除重复元素并对结果进行升序排列; - 如果还需要自定义比较逻辑,则可以选择基于哈希表的数据结构如 `unordered_set` 配合手动排序。 #### 排序策略 对于给定的一组DNA序列(通常表示为长度固定的字符串),按照字典顺序对其进行排序是一个常见需求。C++标准库提供了非常方便的方法来进行此类任务——即利用 `sort()` 函数配合合适的比较器函数对象或 lambda 表达式来指定所需的排序规则。 下面展示了一个简单的例子用于说明如何读取输入、执行必要的预处理步骤(包括但不限于删除冗余条目),最后输出经过整理的结果列表: ```cpp #include <bits/stdc++.h> using namespace std; int main(){ set<string> uniqueDNAs; string line, dna; while(getline(cin,line)){ stringstream ss(line); while(ss>>dna){ uniqueDNAs.insert(dna); // 自动过滤掉重复项 } } vector<string> sortedUnique(uniqueDNAs.begin(),uniqueDNAs.end()); sort(sortedUnique.begin(),sortedUnique.end()); for(auto it=sortedUnique.cbegin();it!=sortedUnique.cend();++it){ cout<<*it; if(next(it)!=sortedUnique.cend())cout<<" "; } } ``` 上述程序片段实现了基本的功能模块:从标准输入流逐行解析得到各个独立的DNA片段;借助 STL 容器特性轻松达成无重复记录维护目的;最终依据字母大小关系重新安排各成员位置后再统一打印出来[^3]。 #### 学习延伸至自然语言处理领域 值得注意的是,在计算机科学特别是机器学习方向上,“上下文”概念同样重要。例如 Word2Vec 这样的技术就是通过考察周围词语环境来捕捉特定词汇的意义特征[^2]。尽管两者应用场景差异显著,但从原理层面看均体现了对局部模式挖掘的关注。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值