洛谷-P1194 买礼物

题目描述

又到了一年一度的明明生日了,明明想要买B样东西,巧的是,这B样东西价格都是A元。

但是,商店老板说最近有促销活动,也就是:

如果你买了第I样东西,再买第J样,那么就可以只花\(K_{I,J}\) 元,更巧的是,\(K_{I,J}\)竟然等于\(K_{J,I}\)

现在明明想知道,他最少要花多少钱。

思路

可以这样想,购买这些东西会构成一个树状关系,除了根之外其他点都按照优惠价格购买(当然优惠价格可能比原价还贵,这里只需要取min即可),那怎样得到除了根之外其他优惠价格的最优解呢?只需要跑一遍最小生成树即可,这样必然会得到一棵树,并且是最优解。

AC代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

const int Maxn = 1005;

struct EDGE {
    int u, v, w;
    EDGE(){}
    EDGE(int u, int v, int w):u(u), v(v), w(w){}
    bool operator < (const EDGE &x) const {
        return w < x.w;
    }
} e[Maxn * Maxn];

int father[Maxn];
int nv, ne, k;

int Find(int x) {
    return father[x] == x ? x : father[x] = Find(father[x]);
}

void Union(int u, int v) {
    int ru = Find(u);
    int rv = Find(v);
    if (ru != rv) {
        father[ru] = rv;
    }
}

int kruskal() {
    for (int i = 0; i <= nv; i++) {
        father[i] = i;
    }
    int t = 0, ans = 0;
    for (int i = 0; i < ne; i++) {
        int u = e[i].u;
        int v = e[i].v;
        int w = e[i].w;
        if (Find(u) != Find(v)) {
            Union(u, v);
            ans += w;
            t++;
            if (t == nv - k) {
                break;
            }
        }
    }
    return t == nv - k ? ans : -1;
}

void solve() {
    scanf("%d %d %d", &nv, &ne, &k);
    int u, v, w;
    for (int i = 0; i < ne; i++) {
        scanf("%d %d %d", &u, &v, &w);
        e[i] = EDGE(u, v, w);
    }
    std::sort(e, e + ne);
    int ans = kruskal();
    if (ans == -1) {
        printf("No Answer\n");
    } else {
        printf("%d\n", ans);
    }
}

int main() {
    solve();
    return 0;
}
posted @ 2021-02-21 16:17  牟翔宇  阅读(89)  评论(0编辑  收藏  举报