POJ-1456 Supermarket【貪心】+【並查集】
阿新 • • 發佈:2018-04-21
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 { intView Codeval; 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) { inti, 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; }
雖然能過樣例,但是還有一些情況沒有想到。比如,不一定要過期時間越早的商品越先銷售,因為,如果後面有價值更大的商品由於時間的沖突不能賣出的話,完全可以舍棄之前銷售價值最小的商品,來賣這件價值更大的商品。
比如數據 :
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【貪心】+【並查集】