POJ-1456 Supermarket贪心+并查集

Posted is_ok

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ-1456 Supermarket贪心+并查集相关的知识,希望对你有一定的参考价值。

题目链接:http://poj.org/problem?id=1456

 

题目大意:

有N件商品,分别给出商品的价值和销售的最后期限,只要在最后日期之前销售处,就能得到相应的利润,并且销售该商品需要1天时间。

问销售的最大利润。

 

我开始的代码:(贪心策略有问题,因为我当时以为过期时间短的商品要优先卖掉,实际上不是这样的)

 

技术分享图片
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAXN 10000+100

struct node
{
    int val;
    int day;
};

bool mysort(node a, node b)      //按照天数从小到大排序,若天数相同,就按价格从大到小排序
{
    if (a.day != b.day)return a.day < b.day;                 
    return a.val > b.val;                                     
}

int main()
{
    int n;
    while (scanf("%d", &n) != EOF)
    {
        int i, j; int sum = 0;
        node dday[MAXN];
        dday[0].day = 0; dday[0].val = 0;
        for (int i = 1; i <=n; i++)
        {
            scanf("%d%d", &dday[i].val, &dday[i].day);
        }
        sort(dday+1, dday + n+1,mysort);    //注意这里我是从i=1,开始存数据的,所排序的时候也要从i=1开始排序
        int ans = 0;
        for (i = 1; i <= n; i++)
        {
            if (dday[i].day != dday[i - 1].day)
            {
                ans += dday[i].day - dday[i - 1].day-1;    //dday[i-1]到dday[i]之间空闲的天数,可以存起来,留给后面时间冲突的天数使用
                sum += dday[i].val;
            }
            else
            {
                if (ans>0)
                {
                    ans--;                   //若之前有空余的天数,那么可以拿一天留到现在来销售
                    sum += dday[i].val;
                }
            }
        }
        printf("%d\n", sum);
    }
    return 0;
}
View Code

 

 

虽然能过样例,但是还有一些情况没有想到。比如,不一定要过期时间越早的商品越先销售,因为,如果后面有价值更大的商品由于时间的冲突不能卖出的话,完全可以舍弃之前销售价值最小的商品,来卖这件价值更大的商品。

 

比如数据 :

5 1 3 15 2 5 3 20 2 10 1

正确答案为 40 而我的代码答案为35 

 

 

然后换另一种贪心思想

将商品的价值从大到小排序,找到销售的最大期限,用visit数组标记,如果它的期限没有被占用,就在该天销售,如果占用,则从它的前一天开始向前查找有没有空闲的日期,如果有则占用。这样就可以得到最大销售量。


#include<iostream>  
#include<cstdio>  
#include<cstring>  
#include<algorithm>  
using namespace std;
#define N 10010  
bool visit[N];

struct node
{
    int profit, deadline;
}p[N];

bool operator <(node a, node b)
{
    return a.profit > b.profit;
}

int main()
{
    int num;
    int maxprofit, maxdate;
    while (~scanf("%d", &num))
    {
        maxprofit = 0;
        memset(visit, false, sizeof(visit));
        for (int i = 1; i <= num; ++i)
        {
            scanf("%d %d", &p[i].profit, &p[i].deadline);
            maxdate = max(maxdate, p[i].deadline);
        }
        sort(p + 1, p + num + 1);            //注意这里是从p+1开始排序
        for (int i = 1; i <= num; ++i)       //优先价值最大
        {
            if (!visit[p[i].deadline])
            {
                maxprofit += p[i].profit;
                visit[p[i].deadline] = true;
            }
            else
            {
                for (int j = p[i].deadline - 1; j >= 1; --j)
                {
                    if (!visit[j])
                    {
                        maxprofit += p[i].profit;
                        visit[j] = true;
                        break;
                    }
                }
            }
        }
        printf("%d\n", maxprofit);
    }
    return 0;
}

 


 

 并查集做法,原理与上面差不多

#include<iostream>  
#include<cstdio>  
#include<cstring>  
#include<algorithm>  
using namespace std;
#define N 10010  
int pre[N];

struct node
{
    int profit, deadline;
}p[N];

bool operator < (const node& a, const node& b)
{
    return a.profit > b.profit;
}

int find(int x)             //寻找该点的根节点
{
    int root, temp;
    root = x;
    while (root != pre[root])
        root = pre[root];
    while (x != root)       //压缩路径
    {
        temp = pre[x];
        pre[temp] = root;
        x = temp;
    }
    return root;
}

int main()
{
    int num;
    int root;
    int maxprofit;
    while (~scanf("%d", &num))
    {
        maxprofit = 0;
        for (int i = 1; i < N; ++i)        //注意这里i小于的是N,不是num
            pre[i] = i;
        for (int i = 0; i < num; ++i)
            scanf("%d%d", &p[i].profit, &p[i].deadline);
        sort(p, p + num);
        for (int i = 0; i < num; ++i)        
        {
            root = find(p[i].deadline);        
            if (root > 0)
            {
                pre[root] = root - 1;           
                maxprofit += p[i].profit;
            }
        }
        printf("%d\n", maxprofit);
    }
    return 0;
}

2018-04-21 

以上是关于POJ-1456 Supermarket贪心+并查集的主要内容,如果未能解决你的问题,请参考以下文章

POJ 1456 acwing 145 Supermarket [贪心+并查集]

POJ 1456 Supermarket(贪心+并查集)

POJ-1456 Supermarket贪心+并查集

[POJ1456]Supermarket(贪心 + 优先队列 || 并查集)

poj 1456 Supermarket - 并查集 - 贪心

poj1456Supermarket——并查集压缩查找