[CODEVS3366] 矿石
题目描述 Description
经历了千辛万苦,小J找到了N块矿石。这些矿石都有毒性,但只要将两块矿石放在一起,再分开即可解毒。但任一两块矿石都可以互相吸引。为了降低吸引力,小J将他们放入一个直径仅能容下一块矿石,且足够高的木桶中并借此完成消毒。
小J一次可以:
- 将任意一块未消毒矿石放入桶中。
2. 取出桶顶的一块矿石消毒,花费的体力值为桶顶和桶中第二个矿石之间的吸引力。若不是所有矿石都消过毒或都未消过毒,则桶不能为空。
小J想知道最少花费多少体力才可以获得所有矿石。
输入描述 Input Description
第一行,n
第二行,每行n个数,第i块矿石与第j块矿石的吸引力Cij
输出描述 Output Description
一行,最小体力花费
样例输入 Sample Input
3
0 4 2
4 0 3
2 3 0
样例输出 Sample Output
5
数据范围及提示 Data Size & Hint
对于30%的数据,N<=15
对于100%的数据,N<=500
emm...
其实要求每个点都有两边,价值和最小,
不就是最小生成树嘛...
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; int n; struct edge{ int x, y, val; friend bool operator < (edge a, edge b) { return a.val < b.val; } }ed[250005]; int cnt; inline void add(int x, int y, int z) { ed[++cnt] = (edge){x, y, z}; } int fa[505]; int Find(int x){return x==fa[x]?x:fa[x]=Find(fa[x]);} long long ans; int main() { scanf("%d", &n); for (int i = 1 ; i <= n ; i ++) { for (int j = 1 ; j <= n ; j ++) { int x; scanf("%d", &x); if (i == j) continue; add(i, j, x); } } sort (ed + 1, ed + 1 + cnt); for (int i = 1 ; i <= n ; i ++) fa[i] = i; int k = 0; for (int i = 1 ; i <= cnt ; i ++) { int x = ed[i].x, y = ed[i].y; int fx = Find(x), fy = Find(y); if (fx == fy) continue; fa[fx] = fy; ans += ed[i].val; k ++; if (k == n - 1) break; } cout << ans << endl; return 0; }