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; }
虽然能过样例,但是还有一些情况没有想到。比如,不一定要过期时间越早的商品越先销售,因为,如果后面有价值更大的商品由于时间的冲突不能卖出的话,完全可以舍弃之前销售价值最小的商品,来卖这件价值更大的商品。
比如数据 :
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 [贪心+并查集]
[POJ1456]Supermarket(贪心 + 优先队列 || 并查集)