POJ 1456.Supermarket

POJ 1456.Supermarket

Description

A supermarket has a set Prod of products on sale. It earns a profit px for each product x∈Prod sold by a deadline dx that is measured as an integral number of time units starting from the moment the sale begins. Each product takes precisely one unit of time for being sold. A selling schedule is an ordered subset of products Sell ≤ Prod such that the selling of each product x∈Sell, according to the ordering of Sell, completes before the deadline dx or just when dx expires. The profit of the selling schedule is Profit(Sell)=Σx∈Sellpx. An optimal selling schedule is a schedule with a maximum profit. 
For example, consider the products Prod={a,b,c,d} with (pa,da)=(50,2), (pb,db)=(10,1), (pc,dc)=(20,2), and (pd,dd)=(30,1). The possible selling schedules are listed in table 1. For instance, the schedule Sell={d,a} shows that the selling of product d starts at time 0 and ends at time 1, while the selling of product a starts at time 1 and ends at time 2. Each of these products is sold by its deadline. Sell is the optimal schedule and its profit is 80. 


Write a program that reads sets of products from an input text file and computes the profit of an optimal selling schedule for each set of products. 
Input

A set of products starts with an integer 0 <= n <= 10000, which is the number of products in the set, and continues with n pairs pi di of integers, 1 <= pi <= 10000 and 1 <= di <= 10000, that designate the profit and the selling deadline of the i-th product. White spaces can occur freely in input. Input data terminate with an end of file and are guaranteed correct.
Output

For each set of products, the program prints on the standard output the profit of an optimal selling schedule for the set. Each result is printed from the beginning of a separate line.
Sample Input

4  50 2  10 1   20 2   30 1

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

Sample Output
80
185

大意:每个商品有价值和过期时间,每天只能卖一件商品,不能卖过期的商品,求最大利润

贪心,对于每个天数t,要在不卖出过期商品的情况下,卖出利润前t大的商品,想法是按照过期时间排序,有过期时间相同的商品时卖出利润最大的

堆中结点的数量t代表前t天已经安排了t个商品卖出

#include <queue>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
static const auto io_sync_off = []() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    return nullptr;
}();

const int maxn = 10005;
struct pro
{
    int val, date;
    bool operator<(const pro &rhs) const
    {
        return date < rhs.date;
    }
} pro[maxn];

int main()
{
    int N;
    while (cin >> N)
    {
        for (int i = 0; i < N; ++i)
            cin >> pro[i].val >> pro[i].date;
        sort(pro, pro + N);

        priority_queue<int> q;//利用小根堆来判断利润最小的
        for (int i = 0; i < N; ++i)
        {
            int val = pro[i].val, date = pro[i].date;
            if (date > q.size())
                q.push(-val);
            else if (date == q.size())//当前已经有date个商品安排卖
            {
                if (val > abs(q.top()))//当前的商品价值更大
                {
                    q.pop();
                    q.push(-val);
                }
            }
        }

        int ans = 0;
        while (!q.empty())
        {
            ans += abs(q.top());
            q.pop();
        }
        cout << ans << endl;
    }
    return 0;
}

另一种贪心策略,首先卖出利润最大的商品,而对每个商品尽量安排晚卖出,也就是尽量少的占用时间

利用并查集,这个并查集维护了一个数组中位置的占用情况,每个位置所在的集合的代表就是从它开始往前数第一个空闲的位置

#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
static const auto io_sync_off = []() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    return nullptr;
}();
const int maxn = 10005;
int f[maxn];
struct pro
{
    int val, date;
    bool operator<(const pro &rhs) const
    {
        return val > rhs.val;
    }
} pro[maxn];

void init()
{
    for (int i = 0; i < maxn; ++i)
        f[i] = i;
}

int find(int x)
{
    return f[x] == x ? x : f[x] = find(f[x]);
}

int main()
{
    int N;
    while (cin >> N)
    {
        init();
        for (int i = 0; i < N; ++i)
            cin >> pro[i].val >> pro[i].date;
        sort(pro, pro + N); //按照价值排序

        int ans = 0;
        for (int i = 0; i < N; ++i)
        {
            int val = pro[i].val, date = pro[i].date;
            int fa = find(date); //当前日期的父节点
            if (fa > 0)          //如果父节点没有被占用
            {
                ans += val;
                f[fa] = fa - 1;
                //fa作为fa-1的子节点,表示fa日期已经安排了商品,可用的最近日期为fa-1
            }
        }
        cout << ans << endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/PegasiTIO/article/details/89023882