P1607 [USACO09FEB]庙会班车Fair Shuttle
题目:逛逛集市,兑兑奖品,看看节目对农夫约翰来说不算什么,可是他的奶牛们非常缺乏锻炼——如果要逛完一整天的集市,他们一定会筋疲力尽的。所以为了让奶牛们也能愉快地逛集市,约翰准备让奶牛们在集市上以车代步。但是,约翰木有钱,他租来的班车只能在集市上沿直线跑一次,而且只能停靠(N(1 ≤N≤20000))个地点(所有地点都以1到N之间的一个数字来表示)。现在奶牛们分成(K(1≤K≤50000))个小组,第i 组有(M_i(1 ≤M_i≤N))头奶牛,他们希望从(S_i)跑到(T_i(1 ≤S_i<T_i≤N))。
由于班车容量有限,可能载不下所有想乘车的奶牛们,此时也允许小里的一部分奶牛分开乘坐班车。约翰经过调查得知班车的容量是(C(1≤C≤100)),请你帮助约翰计划一个尽可能满足更多奶牛愿望的方案。
题解:
对于这道题,很显然是一道贪心,而且我们必须将其考虑为有反悔机制的贪心。首先在每一站,进行一下的判断:
- 将在车上的奶牛可以下车的下车
- 让所有在此站点上车的奶牛上车
- 如果超过数量,将最远目的地的奶牛赶下车
#include <iostream>
#include <set>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 500005;
// 一组牛
struct group {
ll s, t, m;
group() {}
group(ll s, ll t, ll m) : s(s), t(t), m(m) {}
// set内部按照终点站顺序排序
friend bool operator < (const group &a, const group &b) {
return a.t < b.t;
}
} cows[maxn];
ll k, n, c, sum_on_car, ans;
// 在车上的牛的组
multiset<group> cow_set;
// 按照起点站顺序排序
bool cmp(group a, group b) {
if (a.s == b.s) {
if (a.t == b.t) {return a.m < b.m;}
else {return a.t < b.t;}
} else {return a.s < b.s;}
}
int main() {
// 读
cin >> k >> n >> c;
for (int i = 1; i <= k; i ++)
cin >> cows[i].s >> cows[i].t >> cows[i].m;
sort(cows + 1, cows + 1 + k, cmp);
// 从第一站开始遍历上车
for (int i = 1, j = 0; i <= n; i ++) {
multiset<group>::iterator begin_iter = cow_set.begin();
// 到站下车 (终点站顺序排序)
while (begin_iter -> t == i) {
sum_on_car -= begin_iter -> m;
cow_set.erase(begin_iter);
begin_iter = cow_set.begin();
}
// 全部上车
for (int t = j + 1; t <= k && cows[t].s == i; t ++) {
j ++;
cow_set.insert(cows[t]);
sum_on_car += cows[t].m;
ans += cows[t].m;
}
// 人数超标,删最远的牛
while (sum_on_car > c) {
ll delta = sum_on_car - c;
multiset<group>::iterator iter = cow_set.end();
iter --;
ll all_cow_farthest = iter -> m;
cow_set.erase(iter);
if (delta >= all_cow_farthest) {
sum_on_car -= all_cow_farthest;
ans -= all_cow_farthest;
} else {
ll cow_tmp_s = iter -> s, cow_tmp_t = iter -> t, cow_tmp_m = iter -> m;
cow_set.insert(group(cow_tmp_s, cow_tmp_t, all_cow_farthest - delta));
sum_on_car -= delta;
ans -= delta;
}
}
}
cout << ans << endl;
return 0;
}