题目
参考博客
做法一:01背包
首先是用01背包来做,可惜时间有点赶。
时间大概是1000ms,在某OJ上会超时……快读也不行。
POJ可以跑954ms左右,比某OJ快多了,限制还是2000ms(某OJ限制1000ms),逼我用并查集。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include<iostream>
const int N = 1e4 + 10;
using namespace std;
int f[N], n, ans;//f[i]代表在i时间内的最大收益
struct E{
int w, v;//v代表时间
}a[N];
bool operator < (E a, E b) {
return a.v < b.v;
}
inline int read(){
int ret=0;char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch<='9'&&ch>='0') ret=ret*10+ch-'0',ch=getchar();
return ret;
}
int main() {
while (~scanf("%d", &n)){
memset(f, 0, sizeof f);
ans = 0;
for (int i = 1; i <= n; i ++)
a[i].w = read(), a[i].v = read();
sort(a + 1, a + n + 1);//按照时间排序
for (int i = 1; i <= n; i ++)//01背包做法……
for (int j = a[i].v; j; j --) //在时间之内进行更新
f[j] = max(f[j], f[j - 1] + a[i].w),
ans = max(ans, f[j]);//实时记录
printf("%d\n", ans);
}
return 0;
}
做法二:并查集
这是并查集做法
说到这个我感触良多
我看了书之后一直以为是将同一天过期的物品放在一个集合里,每次从中取最大价值的然后将剩下的往前合并……
按这个想法忙活了半天……
看了题解才发现,哦,原来是将已经安排好卖什么的天数放在一个集合就可以了啊?
这么简单?
呵呵呵呵……(又是疯掉的一天)
错误思路害死人啊!!!!!
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
const int N = 10005;
using namespace std;
struct E {
int w, v;
} a[N];
bool operator<(E a, E b) { return a.w > b.w; }
int n, p[N];
int read() {
int ret = 0;
char ch = getchar();
while (ch < '0' || ch > '9') ch = getchar();
while (ch <= '9' && ch >= '0') ret = ret * 10 + ch - '0', ch = getchar();
return ret;
}
int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); }
int main() {
while (cin >> n) {
int maxv = 0;
for (int i = 1; i <= n; i++) {
a[i].w = read(), a[i].v = read();
maxv = max(maxv, a[i].v);
}
sort(a + 1, a + n + 1); //排序
for (int i = 1; i <= maxv; i++) p[i] = i;
int ans = 0;
for (int i = 1; i <= n; i++) {
int target = find(a[i].v); //能卖第i个物品的天数 target
if (target > 0) {
ans += a[i].w;
p[target] = target - 1;
}
}
cout << ans << endl;
}
return 0;
}