1. 程式人生 > >POJ-1456 Supermarket【貪心】+【並查集】

POJ-1456 Supermarket【貪心】+【並查集】

max fff 優先 blank ack ket closed style 時間短

題目鏈接: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【貪心】+【並查集】