腾讯马拉松之 湫湫系列故事——消灭兔子

                                                                        湫湫系列故事——消灭兔子


题目链接:Click Here~

题目分析:

     题目要求,用最小的花费杀死所有的Rabbits。可以从题意就推测出这是一道贪心题,但是不是普通的做法就可以过了,因为数据太大,所以要用到一些数据结构。

     本题可以用多种算法解题。好像本人暂时知道的有三种,贪心+优先队列,贪心+STL,线段树。我是用贪心+STL做的。如果,对其他做法感兴趣的话可以自己百度。

算法思路分析:

    从贪心的角度分析,我们知道要想最后的花费最少。肯定要每一支箭尽最大的可能去射杀血量最大的兔子,且这支箭的花费又要尽最大可能的小。所以,从这两条要求中我们就可以知道,要先对每只箭的价值从小到大排序,使得尽可能的用价值较小的箭去射杀血量尽可能大的兔子。可以看出朴素的方法在1e5的数据小肯定超时。所以,这里我就想到了将兔子的血量先排序。然后,用排完序的价值中的伤害值去查找可以射杀的最大血量的兔子是多少。每次找到一只可以射杀的兔子后,就将这只兔子删除。这种方法查找下去一定会使花费最小。不理解的要自己好好想想。然后,又偷偷的学习了一下STL中的multiset<>的用法。最后,细节部分就自己看下面的代码吧。第三份代码是根据别人提供的思路,我自己写了一遍,一提交居然是171s。上排行榜前几了!!!!太无语了-_-


#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
#include <cstdio>
#include <cstring>
using namespace std;

const int N = 1e5 + 10;
struct Rabbit{
   int hurt,price;
   bool operator < (const Rabbit &a)const{
      return price < a.price;
   }
}list[N];
multiset<int> S;
multiset<int>::iterator it;
void Init(int n,int m)
{
    int hp;
    S.clear();
    for(int i = 0;i < n;++i){    //每只兔子的血量
      scanf("%d",&hp);
      S.insert(hp);
    }
    for(int i = 0;i < m;++i)     //第i支箭的伤害值
      scanf("%d",&list[i].hurt);
    for(int i = 0;i < m;++i)
      scanf("%d",&list[i].price); //第i支箭的价值
    sort(list,list+m);
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        Init(n,m);
        int cnt = 0;
        __int64 ans = 0;
        for(int i = 0;i<m&&cnt<n;++i){
            it = S.upper_bound(list[i].hurt);    
            if(it != S.begin()){
               cnt++;
               ans += list[i].price;  
               S.erase(--it);         //可以射杀兔子的最小花费
            }
        }
        if(cnt == n)
           printf("%I64d\n",ans);
        else
           printf("No\n");
    }
    return 0;
}



#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
#include <cstdio>
#include <cstring>
using namespace std;

const int N = 1e5 + 10;
struct Rabbit{
   int hurt,price;
   bool operator < (const Rabbit &a)const{
      return price < a.price;
   }
}list[N];
multiset<int> S;
multiset<int>::iterator it;
void Init(int n,int m)
{
    int hp;
    S.clear();
    for(int i = 0;i < n;++i){
      scanf("%d",&hp);
      S.insert(-hp);
    }
    for(int i = 0;i < m;++i)
      scanf("%d",&list[i].hurt);
    for(int i = 0;i < m;++i)
      scanf("%d",&list[i].price);
    sort(list,list+m);
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        Init(n,m);
        int cnt = 0;
        __int64 ans = 0;
        for(int i = 0;i<m&&cnt<n;++i){
            it = S.lower_bound(-list[i].hurt);
            if(it != S.end()){
               cnt++;
               ans += list[i].price;  // cout<<"price = " <<list[i].price<<endl;
               S.erase(it);
            }
        }
        if(cnt == n)
           printf("%I64d\n",ans);
        else
           printf("No\n");
    }
    return 0;
}



  优先队列版:


#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;

typedef __int64 LL;
const int N = 1e5 + 5;
struct Rabbit{
   int hurt,price;
   bool operator <(const Rabbit &a)const{
      return price > a.price;
   }
}rab[N];
bool cmp1(int a,int b)     //兔子的血量排序
{
    return a > b;
}
bool cmp2(Rabbit &a,Rabbit &b)   //箭的伤害值排序
{
    return a.hurt < b.hurt;
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        int hp;
        vector<int> ive;
        vector<int>::iterator it;
        priority_queue <Rabbit> Q;
        for(int i = 1;i <= n;++i){
          scanf("%d",&hp);
          ive.push_back(hp);
        }
        for(int i = 1;i <= m;++i)
           scanf("%d",&rab[i].hurt);
        for(int i = 1;i <= m;++i)
           scanf("%d",&rab[i].price);
        sort(ive.begin(),ive.end(),cmp1);
        sort(rab+1,rab+m+1,cmp2);
        LL ans = 0;
        int k = m;
        for(it = ive.begin();it != ive.end();++it){
            while(k&&(*it) <= rab[k].hurt){       //将所有可以杀死第i只兔子的箭都压入到队列中
                 Q.push(rab[k]);
                 k--;
            }
            if(Q.empty())
               break;
            Rabbit tmp = Q.top();                //获取最小花费的箭
            Q.pop();
            ans += tmp.price;
        }
        if(it == ive.end())
          printf("%I64d\n",ans);
        else
          printf("No\n");
    }
    return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值