1129 Recommendation System + 大顶堆 + 结构体小于号重载

刷题时经常会遇到,可以把问题抽象成维护一个有序数组的任务。这个时候大顶堆就是一个不错的选择。其实C++ STL中的set就是一个现成的小顶堆,如果要变成大顶堆,有一个小技巧就是只需要在插入的时候,对元素取相反的极性就可以了,拿出来用的时候再还原回去。

OJ题目链接:https://oj.haizeix.com/problem/285

题解代码:

#include<iostream>
#include<set>
using namespace std;

#define inf 0x3f3f3f3f
#define MAX_M 2000

int a[MAX_M + 5];
typedef pair<int, int> PII;
set<PII> s;
int t = 0; // 时间戳,去重
int n, m, x;

void extract() {
    for (int j = m - 1; j >= 0; j--) {
        a[j] = -(s.begin()->first);
        s.erase(s.begin());
    }   
}
int main() {
    cin >> n >> m;
    for (int i = 0; i < m; i++) {
        cin >> x;
        s.insert(PII(-x, t++));
    }
    for (int i = 1; i < n; i++) {
        extract(); // 这个是第一层的所有元素跟第二层的所有元素配对完以后剩下的大顶堆中的元素作为一二两层元素的代表前往第三层匹配。以此类推,不断合并。
        for (int i = 0; i < m; i++) s.insert(PII(-inf, t++)); // set内部维护有序性的时候是依据pair中的first元素来的
        for (int j = 0; j < m; j++) { 
            cin >> x;
            for (int k = 0; k < m; k++) {
                int y = x + a[k];
                if (y >= -(s.begin()->first)) break;
                s.erase(s.begin());
                s.insert(PII(-y, t++));
            }
        }
    }
    extract();
    for (int i = 0; i < m; i++) {
        i && cout << " ";
        cout << a[i];
    }
    cout << endl;
    return 0;
}

或者当我们需要维护自定义数据结构的有序性的时候,可以重载一下“<”号。

PAT题目链接:https://pintia.cn/problem-sets/994805342720868352/exam/problems/994805348471259136

题解代码:

#include<iostream>
#include<set>
using namespace std;

int a[50005];
struct node {
    int value, cnt;
    node(int a, int b) : value(a), cnt(b) {}
    bool operator < (const node &a) const {
        return (cnt != a.cnt) ? cnt > a.cnt : value < a.value;
    }
};

set<node> s;

int main() {
    int n, k, num;
    scanf("%d%d", &n, &k);
    for(int i = 0; i < n; i++) {
        scanf("%d", &num);
        if (i) {
            printf("%d:", num);
            int j = 0;
            for (auto iter = s.begin(); iter != s.end() && j < k; iter++, j++) {
                printf(" %d", iter->value);
            }
            printf("\n");
        }
        // 维护大顶堆
        auto it = s.find(node(num, a[num]));
        if (it != s.end()) s.erase(it);
        a[num]++;
        s.insert(node(num, a[num]));
    }

    return 0;
}

PAT题目链接:https://pintia.cn/problem-sets/994805342720868352/exam/problems/1478634991737962496

题解代码:

#include<iostream>
#include<vector>
#include<string>
#include<set>
#include<unordered_map>
using namespace std;
#define MAX_N 100000

struct node {
    string id;
    int y, m, d;
    node (string id, int y, int m, int d) : id(id), y(y), m(m), d(d) {}
    // 年纪最大的排最前面
    bool operator < (const node &a) const {
        return (y != a.y) ? y < a.y : (m != a.m ? m < a.m : d < a.d);
    }
};
int cnt;
set<node> s, all;
vector<node> v;
unordered_map<string, int> M;

void extact(string id) {
    int year = stoi(id.substr(7,4));
    int month = stoi(id.substr(11,2));
    int day = stoi(id.substr(13,2));
    M[id] = cnt++;
    v.push_back(node(id, year, month, day));
    all.insert(v[M[id]]);
}

int main() {
    int n, m;
    string id;
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> id;
        extact(id);
    }
    cin >> m;
    for (int i = 0 ; i < m; i++) {
        cin >> id;
        if (M.find(id) != M.end()) {
            s.insert(v[M[id]]);
        } else {
            extact(id);
        }
    }
    if (s.size()) {
        cout << s.size() << endl;
        cout << s.begin()->id << endl;
    } else {
        cout << 0 << endl;
        cout << all.begin()->id << endl;
    }
    return 0; 
}
posted @ 2023-05-01 10:18  江韵阁  阅读(20)  评论(0)    收藏  举报