P1607 [USACO09FEB]庙会班车Fair Shuttle

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)\),请你帮助约翰计划一个尽可能满足更多奶牛愿望的方案。


题解:

对于这道题,很显然是一道贪心,而且我们必须将其考虑为有反悔机制的贪心。首先在每一站,进行一下的判断:

  1. 将在车上的奶牛可以下车的下车
  2. 让所有在此站点上车的奶牛上车
  3. 如果超过数量,将最远目的地的奶牛赶下车
#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;
}
posted @ 2019-07-19 00:58  gyro永不抽风  阅读(158)  评论(0编辑  收藏  举报