• nkrq-4315 购买糖果


    问题描述

            有N 块糖果,每块糖果的价格是a[i]元。
            总共M 元,以及K 张优惠券。
            对于每块糖果,如果使用一张优惠券,则可以以b[i]的优惠价格购买。
            注意每块糖果只能使用一张优惠券,只能购买一次。
            最多可以购买几块糖果?

    输入格式

            第一行三个整数N, K, M
            接下来N 行,每行两个整数,表示a[i]和b [i]。

    输出格式

            一个整数表示答案。

    样例输入

    4 1 7
    3 2
    2 2
    8 1
    4 3

    样例输出

    3

    目录

                                                         基本思路

                                                            代码

                                                         代码注解

    基本思路

    这一道题一看就是一道贪心的题目;(最开始我只写了一次贪心->80分)

    因为这道题有优惠卷这一形式的存在,所以并不能用一次贪心解决问题(不然很难判断这个糖果买不买,用不用优惠卷)所以这里面要思考一下可不可以分成两部分来分别去贪心;

    1. 按优惠价排序并尽量用完优惠卷;
    2. 用结构体优先队列q存储剩下东西的优惠差价,并分别用优惠价排序(Z)原价排序(Y);
    3. 循环比较剩下的该用优惠价还是原价(注意:当差值队列变空仍然要考虑,不能省略);

     所以得到贪心策略:对于以优惠价排序的前n个糖果,能拿多少拿多少,对于剩下的糖果,比较其性价比和原价,选择最后能达到最少价格的一个糖果,并将其标记;

    代码

    1. #include<bits/stdc++.h>
    2. using namespace std;
    3. int n,k,ans=0,vis[100005];
    4. long long my=0,m;
    5. struct lyt{
    6. int a,b;
    7. }x[100005];
    8. struct lyt2{
    9. int a,b,c;
    10. }y[100005],z[100005];
    11. struct cmp{
    12. bool operator()(const int &t1,const int &t2){
    13. return t1>t2;
    14. }
    15. };
    16. priority_queue<lyt,vector<int>,cmp> q;
    17. bool cmp1(lyt a,lyt b){
    18. if(a.b!=b.b)
    19. return a.b<b.b;
    20. return a.a<b.a;
    21. }
    22. bool cmp2(lyt2 a,lyt2 b){
    23. if(a.b!=b.b)
    24. return a.b<b.b;
    25. if(a.a!=b.a)
    26. return a.a<b.a;
    27. return a.c<b.c;
    28. }
    29. bool cmp3(lyt2 a,lyt2 b){
    30. if(a.a!=b.a)
    31. return a.a<b.a;
    32. if(a.b!=b.b)
    33. return a.b<b.b;
    34. return a.c<b.c;
    35. }
    36. int main(){
    37. cin>>n>>k>>m;
    38. for(int i=0;i<n;++i){
    39. cin>>x[i].a>>x[i].b;
    40. }
    41. sort(x,x+n,cmp1);
    42. for(int i=0;i<k;++i){
    43. my+=x[i].b;
    44. if(my>m)
    45. break;
    46. ans++;
    47. }
    48. if(my>m){
    49. cout<<ans<<endl;
    50. return 0;
    51. }
    52. for(int i=0;i<k;++i){
    53. q.push(x[i].a-x[i].b);
    54. }
    55. for(int i=k;i<n;++i){
    56. y[i-k].a=x[i].a;
    57. y[i-k].b=x[i].b;
    58. y[i-k].c=i-k;
    59. z[i-k].a=x[i].a;
    60. z[i-k].b=x[i].b;
    61. z[i-k].c=i-k;
    62. }
    63. sort(y,y+(n-k),cmp3);
    64. sort(z,z+(n-k),cmp2);
    65. memset(vis,0,sizeof(vis));
    66. int a=0,b=0;
    67. for(int i=0;i<n-k;++i){
    68. while(vis[y[a].c])
    69. a++;
    70. while(vis[z[b].c])
    71. b++;
    72. if(!q.empty()){
    73. int fff=q.top();
    74. if(z[b].b+fff<=y[a].a){
    75. my+=z[b].b+fff;
    76. if(my>m)
    77. break;
    78. ans++;
    79. q.pop();
    80. q.push(z[b].a-z[b].b);
    81. vis[z[b].c]=1;
    82. }else{
    83. my+=y[a].a;
    84. if(my>m)
    85. break;
    86. ans++;
    87. vis[y[a].c]=1;
    88. }
    89. }else{
    90. my+=y[a].a;
    91. if(my>m)
    92. break;
    93. ans++;
    94. vis[y[a].c]=1;
    95. }
    96. }
    97. cout<<ans<<endl;
    98. return 0;
    99. }

     代码注解

    变量及数组

    1. n,m,k;//题目中含义
    2. q;//存储优惠价与原价的差价的结构体优先队列
    3. my;//储存已用了的钱数
    4. vis[i]//标记数组
    5. x[i],x[i].a,x[i].b;//第一部分贪心排序数组,原价,优惠价
    6. y[i],z[i]//第二部分排序规则数组
    7. y[i].a,y[i].b,y[i].c//同z数组,分别指原价,优惠价,编号
    8. a,b;//在二部分中指枚举到的两块糖果

    难点代码注解

    1. bool operator()(const int &t1,const int &t2){
    2. return t1>t2;
    3. }
    4. //结构体内嵌比较函数,普通模板为:<返回类型说明符> operator <运算符符号>(<参数表>){<函数体>}
    5. //注意:在过程中因为t1,t2均为常量const,所以值并不会改变
    6. //写这个是为了把优先队列的模式改成从大到小
    1. y[i-k];y+(n-k);
    2. //这两段代码是为了把以n为代表的下标改成以剩下糖果总量为代表的下标

     

  • 相关阅读:
    将java装进u盘指南
    超好用的IDEA插件推荐
    奥克斯空调红外遥控信号编码协议的分析,STC51单片机读红外程序
    vulnhub Potato: 1
    面试题:在大型分布式系统中,给你一条 SQL,让你优化,你会怎么做?
    实战讲解SpringCloud网关接口限流SpringCloudGateway+Redis(图+文)
    MySql 事务隔离实现:
    SwiftUI 如何动态开始和停止播放永久重复(repeatForever)动画
    vue3中如何实现通过点击不同的按钮切换不同的页面
    1965. 丢失信息的雇员
  • 原文地址:https://blog.csdn.net/Kochakin/article/details/125609694