洛谷-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;
}