• CF730I Olympiad in Programming and Sports(反悔贪心)


    这道题非常容易能看出费用流的解法。但是这里要介绍一种反悔贪心的解法(其实是因为最近都在做反悔贪心

    首先容易知道,反悔贪心其实每次就是把决策后的反悔贡献加入优先队列。

    那么这道题我们就可以先强制让对team1贡献大的先当作team1。之后在优先队列里加入反悔贡献(即让这个人去team2产生的贡献 team2[person] - team1[person]

    此时已经有n个人是team1的了。接下来我们处理team2的人。

    team2的人的来源有两个:

    一.从没有加入team1的人选

    二.加入team1的人里面反悔而来

    所以我们可以较容易的写出第二个人的选择条件:

    if (没有加入的人的team1的最大贡献 + 想转去team2的人的最大贡献  > 没有加入的人的team2的最大贡献):

      将没有加入的人加入team1

        把想转去team2的人加入team2

    else:

      将没有加入的人加入team2

    特别讲一下为什么能想到这个if吧。

    现在我们已经强制让team1的人满了。如果一个未加入的人想进入team1那么就需要将team1的人转去team2。

    所以我们进行比较当前这个未加入的人进入team1的贡献 + 一个人去team2所产生的贡献 与 当前的人去team2所产生的贡献进行比较,因为最终目的是让贡献和最大,所以这么做就能保证每次都是产生最大贡献。

    假设当前对team1贡献最大的人和对team2贡献最大的人是同一个人,那么这个式子肯定是成立的。

    假设不是同一个人,显然这么做也会让其贡献最大,所以是不是需要同一个人其实是没有影响的。所以可以两个优先队列维护。

    由于每次需要选出每个未加入人对team1和team2贡献最大的人,所以我们用两个优先队列存储没加入的人。之后用一个优先队列存储反悔操作。(总共是三个优先队列

    以下是AC代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef pair<int, int> pii;
    const int maxn = 3e3 + 10;
    priority_queue<pii, vector<pii>, less<pii> > p1, p2, decide;
    int a[maxn], b[maxn], vis[maxn];
    
    int main() {
        int n, s, p; scanf("%d%d%d", &n, &s, &p);
        int ans = 0;
        for (int i = 1; i <= n ; ++ i) {
            scanf("%d", &a[i]);
            p1.push({a[i], i});
        }
        for (int i = 1; i <= n ; ++ i) {
            scanf("%d", &b[i]);
            p2.push({b[i], i});
        }
        while (s--) {
            int u = p1.top().second;
            p1.pop();
            vis[u] = 1;
            ans += a[u];
            decide.push({b[u]-a[u], u});
        }
        while (p--) {
        //记得吧标记过的出队
    while (vis[p1.top().second]) p1.pop(); while (vis[p2.top().second]) p2.pop(); if (decide.top().first + p1.top().first > p2.top().first) { int u = p1.top().second, v = decide.top().second; p1.pop(); decide.pop(); vis[u] = 1, vis[v] = 2; ans += a[u] + b[v] - a[v]; decide.push({b[u]-a[u], u}); } else { int u = p2.top().second; p2.pop(); vis[u] = 2; ans += b[u]; } } printf("%d ", ans); for (int i = 1; i <= n; ++ i) { if (vis[i] == 1) printf("%d ", i); } printf(" "); for (int i = 1; i <= n; ++ i) { if (vis[i] == 2) printf("%d ", i); } printf(" "); return 0; }
  • 相关阅读:
    AppDelegate减负之常用三方封装
    AppDelegate减负之常用三方封装
    基于AFN封装的带缓存的网络请求
    iOS-创建自己的日志系统
    UIImage 图片处理:截图,缩放,设定大小,存储
    /bin/sh^M: bad interpreter:解决办法
    mac上获取手机的uuid
    iOS PureLayout使用
    iOS集成友盟推送
    完全理解Python的 '==' 和 'is'
  • 原文地址:https://www.cnblogs.com/Vikyanite/p/14642035.html
Copyright © 2020-2023  润新知