zoukankan      html  css  js  c++  java
  • 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; }
  • 相关阅读:
    leetcode 131. Palindrome Partitioning
    leetcode 526. Beautiful Arrangement
    poj 1852 Ants
    leetcode 1219. Path with Maximum Gold
    leetcode 66. Plus One
    leetcode 43. Multiply Strings
    pytorch中torch.narrow()函数
    pytorch中的torch.repeat()函数与numpy.tile()
    leetcode 1051. Height Checker
    leetcode 561. Array Partition I
  • 原文地址:https://www.cnblogs.com/Vikyanite/p/14642035.html
Copyright © 2011-2022 走看看