题目描述
你的朋友最近完成了烹饪课的学习,现在他想通过做出一个美味的甜点来在他的同学面前展现他的学习成果。
他想出了一种叫樱桃网的甜点。
为了制作这道菜,他准备了N个樱桃,依次编号为1~N。
在他的甜点中,任意两个樱桃之间都存在着一条用糖构成的链条,将它们直接互相连接。
糖链呈红色或黑色,这取决于它们的含糖量。
每条黑色糖链含有一个单位的糖,每条红色糖链含有两个单位的糖。
在甜点完成之后,他发现甜点做的太甜了,而他的同学们都不喜欢吃含糖量过高的食物。
他现在遇到了困惑,特地向你求助。
请你帮助他找出他应该去掉哪些糖链,使得这道菜的每对樱桃之间都能通过糖链直接或间接连接的同时,含糖量能够尽可能的最低?
输出这个含糖量的最小值。
输入格式
第一行包含整数T,表示共有T组测试数据。
每组数据第一行包含两个整数N和M,分别表示樱桃数量以及黑色糖链数量。
接下来M行,每行包含两个整数Ci
和Di,表示编号为Ci和Di
的两个樱桃之间存在一条黑色糖链。
注意:如果任意两个樱桃之间,没有被黑色糖链连接,那么说明它们之间由一条红色糖链连接。
输出格式
每组数据输出一个结果,每个结果占一行。
结果表示为“Case #x: y”,其中x是组别编号(从1开始),y为含糖量的最小值。
数据范围
1≤T≤100
,
M≤N∗(N−1)/2
1≤Ci,Di≤N,
Ci≠Di,
同一组数据内,所有{Ci, Di}对都互不相同。
1≤N≤105,
0≤M≤105
输入样例:
2
2 1
1 2
3 1
2 3
输出样例:
Case #1: 1
Case #2: 3
样例解释
在样例#1中,只有两个樱桃,它们之间由一个黑色糖链连接,去掉任何糖链都会使樱桃之间断连。
所以,含糖量的最小值为1。
在样例#2中,一种可行的方法是保留1和2之间的红色糖链以及2和3之间的黑色糖链。
所以,含糖量的最小值为3。
难度: 简单
时/空限制: 1s / 64MB
总通过数: 43
总尝试数: 92
来源: Google Kickstart2019 Round E Problem A
算法标签
翻译过来大概是这样
给定一个
n个点
不一定联通的图,
边权全部是1
连个联通块需要2
的边权连接
问联通所有点的最小边权是多少 ?
- 直接 d f s dfs dfs求联通块个数,再算一下答案就行了
- 或者用最小生成树求联通块(
因为标签打的是最小生成树) - 并查集统计联通块个数的方法 : for一遍
fa[]
数组(爹数组),统计fa[i]==i
的个数就是联通块个数 - 全联通
ans=n-1
- 不连通
ans=(n-1) + (cnt-1)
cnt是联通块的个数
/**
]]]` ]]]` ]]]] ,]]]` .]@@@\]. ,]]` ]]]` ]]]]]]].
.@@@^ /@@^ \@@\ ,@@@` ,@@@@@@@@` =@@@\ @@@^ @@@@@@@@
@@@^/@@^ ,@@@@@/ ,@@@. =@@@@@` @@@^ @@ @@
\@@@@` =@@@\ =@@^ =@@^,@@\@@@^ @@@@@@@@@.
@@@^ /@@@@@@` =@@@. =@@^ .\@@@@^ @@ @@
@@@^ *@@@` ,@@@^ =@@@@@@@@^ =@@^ \@@@^ @@@@@@@@@`
[[[` .[[[` .[[[` ,[@@@/[` ,[[` ,[[` [[[[[[[.
*/
#define debug
#ifdef debug
#include <time.h>
#include "/home/majiao/mb.h"
#endif
#include <iostream>
#include <algorithm>
#include <vector>
#include <string.h>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <math.h>
#define MAXN ((int)1e5+7)
#define ll long long
#define INF (0x7f7f7f7f)
#define fori(lef, rig) for(int i=lef; i<=rig; i++)
#define forj(lef, rig) for(int j=lef; j<=rig; j++)
#define fork(lef, rig) for(int k=lef; k<=rig; k++)
#define QAQ (0)
using namespace std;
#define show(x...) \
do { \
cout << "\033[31;1m " << #x << " -> "; \
err(x); \
} while (0)
void err() { cout << "\033[39;0m" << endl; }
template<typename T, typename... A>
void err(T a, A... x) { cout << a << ' '; err(x...); }
namespace FastIO {
char print_f[105];
void read() { }
void print() { putchar('\n'); }
template <typename T, typename... T2>
inline void read(T &x, T2 &... oth) {
x = 0;
char ch = getchar();
ll f = 1;
while (!isdigit(ch)) {
if (ch == '-') f *= -1;
ch = getchar();
}
while (isdigit(ch)) {
x = x * 10 + ch - 48;
ch = getchar();
}
x *= f;
read(oth...);
}
template <typename T, typename... T2>
inline void print(T x, T2... oth) {
ll p3=-1;
if(x<0) putchar('-'), x=-x;
do{
print_f[++p3] = x%10 + 48;
} while(x/=10);
while(p3>=0) putchar(print_f[p3--]);
putchar(' ');
print(oth...);
}
} // namespace FastIO
using FastIO::print;
using FastIO::read;
int n, m, Q, K, pre[MAXN], sz;
struct Edge {
int u, v, w;
bool operator < (const Edge& y) const {
return w < y.w;
}
} ed[MAXN];
void init() {
sz = 0;
for(int i=1; i<=n; i++) pre[i] = i;
}
int fa(int x) {
return (x==pre[x]) ? x : (pre[x]=fa(pre[x]));
}
void union_xy(int x, int y) {
int rx = fa(x), ry = fa(y);
if(rx != ry)
pre[ry] = rx;
}
void krsxxx() {
// sort(ed+1, ed+sz+1); //初始边权全是1,可以不排序
for(int i=1; i<=sz; i++) {
int rx = fa(ed[i].u), ry = fa(ed[i].v);
if(rx == ry) continue ;
union_xy(ed[i].u, ed[i].v);
}
}
int main() {
#ifdef debug
freopen("test", "r", stdin);
// freopen("out_main", "w", stdout);
clock_t stime = clock();
#endif
read(Q);
int cas = 0;
while(Q--) {
read(n, m);
init();
for(int i=1; i<=m; i++) {
++ sz;
read(ed[sz].u, ed[sz].v);
ed[sz].w = 1;
}
krsxxx();
int cnt = 0;
for(int i=1; i<=n; i++)
if(pre[i] == i) cnt ++;
if(cnt == 1)
printf("Case #%d: %d\n", ++cas, n-1);
else
printf("Case #%d: %d\n", ++cas, (n-1) + (cnt-1));
}
#ifdef debug
clock_t etime = clock();
printf("rum time: %lf 秒\n",(double) (etime-stime)/CLOCKS_PER_SEC);
#endif
return 0;
}