POJ 1456 Supermarket (贪心 && 并查集优化)
题意 : 超市里有n个产品要卖, 每个产品都有一个截至时间dx(从开始卖时算起), 只有在这个截至时间之前才能卖出并且获得率润dy。有多个产品, 所有可以有不同的卖出顺序, 每卖一个产品要占用1个单位的时间, 问最多能卖出多少利润。
分析 : 如果我们先不考虑商品的利润, 假设我们有A、B、C三件商品, 过期时间分别是1, 2, 3, 我们要保证的是每件商品尽量在过期前卖出去, 可以发现如果我要保证卖出的数量最多, 那很显然要将C就在第三天卖出(也就是刚刚好到保质期), A和B也是一样, 才能将三件商品全部卖出, 会发现对于时间来说, 我们都要尽量将商品的卖出时刻尽量靠近其过期时间, 这样才能保证数量的最优, 实际也可以这样考虑, 既然每一个商品都要占用一个单位的时间, 那一开始当然是保质期最短的先卖出去最好了。既然这样能保证数量最优, 那接下来只有一个因素影响最后的单个商品利润影响最后的总收入了, 所以可以考虑将商品按利润从小到大排好序, 然后用一个标记数组来记录某一时间是否已经被占用(比如有两件商品的过期日期都是2), 如果被占用, 则将第二件商品的销售时间点在过期时间往后移一个时间点, 如果后一个时间点同样被占用, 就再继续往后移动, 直到0 即没有时间可以被占用了。
未优化贪心 :
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn = 10001;
int vis[maxn];
struct pro{
int val, dead;
};
pro arr[maxn];
bool cmp(const pro fir, const pro sec)
{
return fir.val > sec.val;
}
int main(void)
{
int n;
while(~scanf("%d", &n)){
memset(vis, 0, sizeof(vis));
for(int i=0; i<n; i++){
scanf("%d%d", &arr[i].val, &arr[i].dead);
}
sort(arr, arr+n, cmp);
int ans = 0;
for(int i=0; i<n; i++){
if(!vis[arr[i].dead]){
ans += arr[i].val;
vis[arr[i].dead] = 1;
}else{
for(int j=arr[i].dead-1; j>=1; j--){
if(!vis[j]){
ans += arr[i].val;
vis[j] = 1;
break;
}
}
}
}
printf("%d\n", ans);
}
return 0;
}
优化 : 如果每一次都用一个for循环往后移动找还没被占用的时间点, 时间将是线性的, 假如我n个商品的保质期都是A, 当n很大的时候, 这就有点慢了。实际上, 每一个时间的推移可以想象成这样 A->(A-1)->(A-2)->(A-3).....每一次可以用的都要向后推移一个单位, 看到这个结构有没有很类似并查集?很多的节点连着根, 实际就是每一次推移, 就是给这条类似链表的结构增加一个(A-Num)的根结点, 也就是每一次用完一个时间点, 我将下一个可以用的时间点作为根连到这个链状机构上, 下一次遇到A或者(A-K) K<Num那直接找这个根节点便是可用时间点, 如果我能对其进行路径压缩, 就可以很快的找到可用的时间点(根)
贪心+并查集优化 :
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 10001;
int f[maxn], n;
struct pro
{
int val, dead;
friend bool operator < (const pro& fir, const pro& sec){
return fir.val > sec.val;
}
}arr[maxn];
int findset(int x)
{
int root = x;
while(root != f[root]) root = f[root];
int temp;
while(root != f[x]){
temp = f[x];
f[x] = root;
x = temp;
}
return root;
}
inline void initialize(int N)
{
for(int i=0; i<=N; i++)
f[i] = i;
}
int main()
{
while(~scanf("%d", &n)){
int MAX = -1;
for(int i=0; i<n; i++){
scanf("%d%d", &arr[i].val, &arr[i].dead);
if(MAX<arr[i].dead) MAX = arr[i].dead;
}
initialize(MAX);
sort(arr, arr+n);
int ans = 0;
for(int i=0; i<n; i++){
int temp = findset(arr[i].dead);
if(temp > 0){
f[temp] = temp-1;
ans += arr[i].val;
}
}
printf("%d\n", ans);
}
return 0;
}