AcWing:145. 超市(贪心 + 小根堆 or 贪心 + 并查集)

超市里有N件商品,每个商品都有利润pipi和过期时间didi,每天只能卖一件商品,过期商品(即当天di<=0di<=0)不能再卖。

求合理安排每天卖的商品的情况下,可以得到的最大收益是多少。

输入格式

输入包含多组测试用例。

每组测试用例,以输入整数N开始,接下里输入N对pipi和didi,分别代表第i件商品的利润和过期时间。

在输入中,数据之间可以自由穿插任意个空格或空行,输入至文件结尾时终止输入,保证数据正确。

输出格式

对于每组产品,输出一个该组的最大收益值。

每个结果占一行。

数据范围

0N100000≤N≤10000,
1pi,di100001≤pi,di≤10000

输入样例:

4  50 2  10 1   20 2   30 1

7  20 1   2 1   10 3  100 2   8 2
   5 20  50 10

输出样例:

80
185

 

算法:贪心 + 小根堆

题解:根据题意,一天只能卖一个商品,那么,我们就可以用贪心的思想来实现,用小根堆(可以用优先队列来实现,不一定要手写)来维护最大值。

 

优先队列实现小根堆:

 

#include <iostream>
#include <cstdio>
#include <queue>
#include <functional>
#include <algorithm>

using namespace std;

const int maxn = 1e5+7;

struct node {
    int pi, di;
}arr[maxn];

priority_queue<int, vector<int>, greater<int> > p;      //建立从小到大的优先队列(小根堆)

bool cmp(node a, node b) {
    return a.di < b.di;
}

int main() {
    int n;
    while(~scanf("%d", &n)) {
        for(int i = 1; i <= n; i++) {
            scanf("%d %d", &arr[i].pi, &arr[i].di);
        }
        sort(arr + 1, arr + n + 1, cmp);
        for(int i = 1; i <= n; i++) {
            if(arr[i].di > p.size()) {      //如果商品的过期天数大于当前天数,就直接进入队列
                p.push(arr[i].pi);
            } else if(arr[i].di == p.size() && arr[i].pi > p.top()) {       //当商品的过去天数等于当前天数的时候,就比较一下当前商品是否比队列中最小的商品大,如果是就进入队列
                p.pop();
                p.push(arr[i].pi);
            }
        }
        int ans = 0;
        while(!p.empty()) {
            ans += p.top();
            p.pop();
        }
        printf("%d\n", ans);
    }
    return 0;
}

 

 

二叉堆实现小根堆:

 

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;

const int maxn = 1e5+7;

struct node {
    int pi, di;
}arr[maxn];
int heap[maxn];
int tot;

bool cmp(node a, node b) {
    return a.di < b.di;
}

void up(int n) {
    while(n > 1) {
        if(heap[n] < heap[n / 2]) {
            swap(heap[n], heap[n / 2]);
        }
        n /= 2;
    }
}

void insert(int val) {
    heap[++tot] = val;
    up(tot);
}

void down(int n) {
    int s = n * 2;
    while(s <= tot) {
        if(s < tot && heap[s] > heap[s + 1]) {  //找出左右子树中较小的那个
            s++;
        }
        if(heap[s] < heap[n]) {
            swap(heap[s], heap[n]);
        }
        n = s;
        s = 2 * n;
    }
    
}

void update(int val) {
    heap[1] = val;
    down(1);
}

int main() {
    int n;
    while(~scanf("%d", &n)) {
        for(int i = 1; i <= n; i++) {
            scanf("%d %d", &arr[i].pi, &arr[i].di);
        }
        sort(arr + 1, arr + n + 1, cmp);
        tot = 0;
        for(int i = 1; i <= n; i++) {
            if(arr[i].di > tot) {
                insert(arr[i].pi);
            } else if(arr[i].di == tot && arr[i].pi >heap[1]) {
                update(arr[i].pi); 
            }
        }
        int ans = 0;
        for(int i = 1; i <= tot; i++) {
            ans += heap[i];
        }
        printf("%d\n", ans);
    }
    return 0;
}

 并查集:

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>

using namespace std;

const int maxn = 1e4+5;

struct node {
    int weight, date;
    friend bool operator < (node a, node b) {
        if(a.weight == b.weight) {
            return a.date > b.date;
        }
        return a.weight > b.weight;
    }
};

vector<node> v;
int f[maxn];

int find(int x) {
    if(f[x] != x) {
        return f[x] = find(f[x]);
    }
    return f[x];
}

int main() {
    int n;
    while(~scanf("%d", &n)) {
        v.clear();
        int maxe = 0;
        for(int i = 0; i < n; i++) {
            int x, y;
            scanf("%d %d", &x, &y);
            v.push_back((node){x, y});
            maxe = max(maxe, y);
        }
        for(int i = 0; i <= maxe; i++) {
            f[i] = i;
        }
        sort(v.begin(), v.end());    //按权值从大到小排序
        int size = v.size();
        int ans = 0;
        for(int i = 0; i < size; i++) {
            int w = v[i].weight;
            int d = v[i].date;
            int pos = find(d);    //找到当前日期的最佳位置
            if(pos > 0) {    //如果该位置没有出界,那么就可以使用
                ans += w;
                f[pos] = pos - 1;
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

 

posted @ 2019-08-06 16:12  不会fly的pig  阅读(305)  评论(0编辑  收藏  举报