本蒟蒻的第一篇题解
呃呃呃,先简化题意,大概的意思就是说,让你把m条铁路的其中一条铁路炸掉,使得这n个城市中有两个城市不连通(用并查集的思想就是让你把一条边给抠掉,使得有至少两个连通块)。
如果不看标签,很快就可以想到一种思路:
先输入m条路径,每条路径都会有两个不同的城市,用桶的思想统计每个城市出现的次数,如果某个城市只出现了一次,那么那个城市所在的那一条铁路就是key road
于是便兴致勃勃地打出了代码:
#include<bits/stdc++.h>
using namespace std;
#define SF scanf
#define PF printf
int f[155], u[5005], v[5005];//f数组是桶,记录每个城市出现的次数,u数组是起点,v数组是终点
int main() {
int n, m;
SF("%d%d", &n, &m);
for(int i = 1; i <= m; i++) {
SF("%d%d", &u[i], &v[i]);
f[u[i]]++;//统计城市出现次数
f[v[i]]++;//同上
}
for(int i = 1; i <= n; i++) {
if(f[i] == 1) {//如果某个城市只出现了一次
PF("%d %d\n", u[i], v[i]);//输出他所在的路径
}
}
return 0;
}
交一下试试?
呃呃呃,这可是道黄题啊,能让你这么轻松地水过去?
为什么会WA呢?
因为那个并查集的思想,是让你搞两个连通块出来,又不是让你去隔离某个城市
所以我们要换个思路?
没错,就是克鲁斯卡尔最小生成树(别问我为什么不写并查集,问就是懒得写,套模板不香吗)
问题又来了,怎么去巧妙地改一下这个模板呢?
很简单,我们把两个城市之间的路径设为1,就代表没有被炸;设为INT_MAX,就代表被炸了
like this:
for(int i = 1; i <= m; i++) {
int u, v;
SF("%d%d", &u, &v);
s[i].u = u;
s[i].v = v;
s[i].w = 1;//刚开始时铁路都没有被炸
}
之后去一个个枚举炸哪个铁路
就像这样:
for(int i = 1; i <= m; i++) {
s[i].w = INT_MAX;//将第i个铁路炸掉
KAL(i);//模板
s[i].w = 1;//记得回溯哦~
}
那么KAL里面又该怎么改呢?
我们知道,只要两个城市不在一个连通块里面,那么就可以选择这两个城市之间的路径进行连通。我们又知道,当两个城市之间的路径不为INT_MAX时,也可以选择进行连通,那么我们就可以得到以下的改了一点点的模板代码:
void KAL(int q) {
for(int i = 1; i <= n; i++) {//初始化并查集
fa[i] = i;
}
int sum = 0;
for(int i = 1; i <= m; i++) {//遍历每一条边
int fu = fun(s[i].u);
int fv = fun(s[i].v);
if(fu != fv && s[i].w != INT_MAX) {//上面的判断条件
sum++;
fa[fu] = fv;//合并并查集
if(sum == n - 1) return;//如果连通的边数是n-1,则代表一定是且仅是一个连通块
}
}
PF("%d %d\n", s[q].u, s[q].v);//如果遍历完所有边后还未连通,则说明至少有两个连通块,直接输出
}
再次开开心心的提交
再次陷入沉思……
要不再去题目中看看?
请注意:输出时,所有的数对 <a,b>必须按照 a 从小到大排序输出;如果a 相同,则根据 b 从小到大排序。
又没有认真读题吧
咳咳,问题不大,只需要我们答案先储存到数组里,然后写个cmp,最后再统一输出就行了
ans[++r].u = s[q].u;//储存答案
ans[r].v = s[q].v;
bool comp(node a, node b) {//快乐的cmp函数
return a.u == b.u ? a.v < b.v : a.u < b.u;
}
sort(ans + 1, ans + 1 + r, comp);//排序
for(int i = 1; i <= r; i++) {//统一地输出
PF("%d %d\n", ans[i].u, ans[i].v);
}
又再次开开心心地提交
为什么呢?
最后,我实在想不出来了,去下载了一个数据,发现a一定要比b小
于是,我重振旗鼓,再次稍微修改了一下:
ans[++r].u = min(s[q].u, s[q].v);//起点取小的
ans[r].v = max(s[q].u, s[q].v);//终点取大的
提交后
5ms,不知道是数据水还是代码跑的快
就这样,你就AC了一道黄题
其实这样一点点地把一道题做对的过程挺好的(开始煽情呜呜呜)
OK,see you,bye!
欸,好像少了点什么
哦,我懂了
代码时刻
#include<bits/stdc++.h>
using namespace std;
#define SF scanf
#define PF printf
struct node {
int u, v, w;
}s[10005], ans[10005];
int fa[155];
int fun(int x) {
if(fa[x] == x) return x;
return fa[x] = fun(fa[x]);
}
int n, m, r;
bool cmp(node a, node b) {
return a.u == b.u ? a.v < b.v : a.u < b.u;
}
void KAL(int q) {
for(int i = 1; i <= n; i++) {
fa[i] = i;
}
int sum = 0;
for(int i = 1; i <= m; i++) {
int fu = fun(s[i].u);
int fv = fun(s[i].v);
if(fu != fv && s[i].w != INT_MAX) {
sum++;
fa[fu] = fv;
if(sum == n - 1) return;
}
}
ans[++r].u = min(s[q].u, s[q].v);
ans[r].v = max(s[q].u, s[q].v);
}
bool comp(node a, node b) {
return a.u == b.u ? a.v < b.v : a.u < b.u;
}
int main() {
SF("%d%d", &n, &m);
for(int i = 1; i <= m; i++) {
int u, v;
SF("%d%d", &u, &v);
s[i].u = u;
s[i].v = v;
s[i].w = 1;
}
sort(s + 1, s + 1 + m, cmp);
for(int i = 1; i <= m; i++) {
s[i].w = INT_MAX;
KAL(i);
s[i].w = 1;
}
sort(ans + 1, ans + 1 + r, comp);
for(int i = 1; i <= r; i++) {
PF("%d %d\n", ans[i].u, ans[i].v);
}
return 0;
}
拒绝复制,从我做起