题目描述
地主的傻儿子豆豆家很大很大,由很多个区域组成。其中有不少封闭的区域,豆豆觉得很不爽于是决定拆墙,把家打通使得他可以访问到每一个区域(包括家外面无限大的区域)。我们用
N
个端点和
现在豆豆想知道他最少一共需要花费多少力气?
输入格式
第一行一个整数
T
表示数据组数。
每组数据第一行两个整数
接下来 N 行每行两个整数
Xi
和 Yi。
接下来 M 行每行三个整数 Ai,Bi,Ci。
输出格式
每组数据输出两个整数表示最少拆除的墙的数量和拆墙最少需要多少的力气。注意所有墙可能不互相连通。
样例数据
Input
1
4 4
-1 -1
-1 1
1 1
1 -1
1 2 1
2 3 2
3 4 1
4 1 2
Output
1 1
备注
[数据范围]
对于
30%
的数据,
N,M≤10
,
T=10
;
对于
70%
的数据,
N≤5000,M≤10000
,
T=1
;
对于
100%
的数据,
N≤100000;
M≤200000
;
ΣN≤300000;
ΣM≤500000
;
|xi|,|yi|≤100000;
0≤wi≤10000,
T=3
。
题解 :
说实话这道题,真的坑,主要是坑了很多人的时间,这道题讲真出题人就想拿这道题来骗人, 显然这个x, y没有什么卵用, 样例又给的是个框, 让我多想了。
回归正题, 通过题意我们可以很容易发现,最终我们剩下的图一定是颗树, 且我们要删最小的边, 于是我们可以发现,最优的情况就是最大生成树, 于是我们就按照常理写, 有人会问为什么不考虑不在一个联通块, 话说你写的时候完全不用考虑啊, 你只是关心你并查集的时候这些的点是不是在同一个并查集就行了。
代码 :
这里我按秩合并了的
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <ctime>
#include <map>
#include <vector>
#define LL long long
using namespace std;
inline int read() {
int i = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-') f = -1; ch = getchar();
}
while(ch >= '0' && ch <= '9') {
i = (i << 3) + (i << 1) + ch - '0'; ch = getchar();
}
return i * f;
}
const int MAXN = 1e5 + 5;
const int MAXM = 2e5 + 5;
struct point {
int from, to, len;
};
point edge[MAXM * 2];
int fa[MAXN], r[MAXN], x[MAXN], y[MAXN];
inline int getfather(int x) {
return fa[x] == x ? x : fa[x] = getfather(fa[x]);
}
inline void make_set(int x) {
fa[x] = x; r[x] = 0;
}
inline bool comp(const point & a, const point & b) {
return a.len > b.len;
}
inline int Union(int x, int y) {
int gx = getfather(x);
int gy = getfather(y);
if(gx == gy) return 0;
if(r[gx] < r[gy])
fa[gx] = gy;
else {
if(r[gx] == r[gy]) ++r[gx];
fa[gy] = gx;
}
return 1;
}
int main() {
freopen("wall.in", "r", stdin);
freopen("wall.out", "w", stdout);
int times = read();
while(times--) {
memset(r, 0, sizeof(r));
int n = read(), m = read();
for(int i = 1; i <= n; ++i) x[i] = read(), y[i] = read();
for(int i = 1; i <= m; ++i) {
edge[i].from = read(), edge[i].to = read(); edge[i].len = read();
}
sort(edge + 1, edge + m + 1, comp);
LL ans = 0; int num = 0;
for(int i = 1; i <= n; ++i) make_set(i);
for(int i = 1; i <= m; ++i) {
if(!Union(edge[i].from, edge[i].to)) ans += edge[i].len, ++num;
}
cout<<num<<' '<<ans<<'\n';
}
}
本题结束 :
感谢阅读本篇文章,喜欢的话,点个赞吧,你的鼓励就是我最大的动力
有什么意见,尽情发表吧。