题目:逛逛集市,兑兑奖品,看看节目对农夫约翰来说不算什么,可是他的奶牛们非常缺乏锻炼――如果要逛完一整天的集市,他们一定会筋疲力尽的。所以为了让奶牛们也能愉快地逛集市,约翰准备让奶牛们在集市上以车代步。但是,约翰木有钱,他租来的班车只能在集市上沿直线跑一次,而且只能停靠\(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; }