POJ 3622 Gourmet Grazers (数据结构)

Description

Like so many others, the cows have developed very haughty tastes and will no longer graze on just any grass. Instead, Farmer John must purchase gourmet organic grass at the Green Grass Grocers store for each of his N (1 ≤ N ≤ 100,000) cows.

Each cow i demands grass of price at least Ai (1 ≤ Ai ≤ 1,000,000,000) and with a greenness score at least Bi (1 ≤ Bi ≤ 1,000,000,000). The GGG store has M (1 ≤ M ≤ 100,000) different types of grass available, each with a price Ci (1 ≤ Ci ≤ 1,000,000,000) and a greenness score of Di (1 ≤ Di ≤ 1,000,000,000). Of course, no cow would sacrifice her individuality, so no two cows can have the same kind of grass.

Help Farmer John satisfy the cows’ expensive gourmet tastes while spending as little money as is necessary.

Input

  • Line 1: Two space-separated integers: N and M.
  • Lines 2..N+1: Line i+1 contains two space-separated integers: Ai and Bi
  • Lines N+2..N+M+1: Line i+N+1 contains two space-separated integers: Ci and Di

Output

  • Line 1: A single integer which is the minimum cost to satisfy all the cows. If that is not possible, output -1.

题意

有 N 头牛与 M 种草,给定第 i 头要吃的草的最低价格为 Ai ,草的最低质量为 Bi 。M 种草每种草的价格为 Ci ,质量为 Di 。同时每头牛吃的草的种类要不同,问使得每头牛都吃到满足条件的草所需要花费的最少价格?

分析

用点数据结构来模拟实现即可。

通用做法为:二维数组记录牛要吃的草的要求和草的规格, ci, si 。均按照草的质量从大到小排序。通过枚举排序后数组 ci ,对于每个 ci , 将数组 s 中满足 ci.y<=si.y 加入可以实现 O(logn) 插入,查找,删除的数据结构中(个人选择了使用 set),HINT: 由于数组已经排序,查找数组 s 中满足条件的数只需线性扫描即可,具体请看代码来理解。

之后,对上述枚举的 ci ,在集合中查找最小的满足大于等于 ci.x 的数。 记录对答案的贡献,并从集合中删除该数。

注意: 使用 STL 的 lower_bound(start, end, value) 与使用 set 中的函数 set::lower_bound(value) 。两者的效率是不同的。set 中的 lower_bound(value) 函数可以做到 O(logn) 的二分查找,但使用 lower_bound(start, end, value) 只能用迭代器的线性扫描。复杂度完全不同。

代码

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<set>
using namespace std;
const int N = 100000 + 10;
const int M = 100000 + 10;
int n, m;
long long ans = 0;
struct Node {
    int x, y;
}c[N], s[M];
bool cmp(Node a, Node b) {
    if(a.y == b.y)  return a.x < b.x;
    return a.y > b.y;
}
multiset<pair<int, int> > st;
multiset<pair<int, int> >::iterator it;
bool operator<(pair<int, int> a, pair<int,int> b) {
    return a.first < b.first;
}
int main()
{
    for(;scanf("%d %d",&n,&m)!=EOF;)
    {
        ans = 0;
        st.clear();
        for(int i=0;i<n;i++)
            scanf("%d %d",&c[i].x, &c[i].y);
        for(int i=0;i<m;i++)
            scanf("%d %d",&s[i].x, &s[i].y);
        sort(c, c+n, cmp);
        sort(s, s+m, cmp);
        int idx = 0;
        for(int i=0;i<n;i++)
        {
            while(idx < m && s[idx].y >= c[i].y)
            {
                st.insert(make_pair(s[idx].x, idx));
                idx++;
            }
            it = st.lower_bound(make_pair(c[i].x, 0));
            if(it == st.end()) {
                ans = -1;   break;
            }
            ans += it->first;
            st.erase(it);
        }
        printf("%I64d\n",ans);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值