好久没练了,忽然感觉对并查集陌生了好多,今天专门找题来练一下才发现之前掌握的并查集太片面了。
国王的烦恼,这个题大意是:n个岛屿,有m条大桥,每条大桥连接两个岛屿,可能有两个相同岛屿之间有多条大桥的情况。
输入:n,m,
m行桥,每行包含: 岛屿a,岛屿b,该桥剩余工作的天数。
说:每断裂一所能够导致原本两座可以联通的桥无法直接也无法再间接到达彼此后,人们就抗议一天。问:一共抗议几天?
一开始知道要用并查集(因为先看的百度题解)但是所有的题解看完一遍都感觉还是不明白为什么。
解剖一下大佬的思路外加自己搞懂的过程:
首先,将桥按照剩余天数递减排列,然后开始遍历所有的桥,网上的思路是从遍历的第一座桥开始,判断他俩原来是否来连通,如果不联通并且抗议的这天和上一次抗议的那天不是一天就把结果++,!!到着我就不明白了,为什么要判断或者怎么能够判断到他俩原来连不连通,肯定不联通啊,这才遍历第一个而且咱之前啥工作也没做啊,除了排序,,,没错,就是排序,我们做了排序啊!!,递减排序,也就意味着每次遍历到的都是咱剩下未遍历得所有桥中最晚断裂的,从咱排序的第一座也就是事件最后断裂的桥一定会引起抗议加一天,然后再将他连接好,往下进行遍历,此时也就满足了下一个桥段断裂时情况判断的条件(此时还有哪些桥是联通的),至于与上一次抗议的天数不等这个大家都懂的的啦!上代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<algorithm>
#include<cstring>
using namespace std;
int pre[10000+10]={0};
typedef struct node{
int x;
int y;
int day;
}way;
bool cmp(way a, way b){
return a.day>b.day;
}
int Find(int x){
if(x==pre[x])return x;
return pre[x]=Find(pre[x]);
}
int union1(int x,int y){
x = Find(x);
y = Find(y);
if(x!=y){
pre[x] = y;
return 1;
}
return 0;
}
int main(){
way ww[100000+10];
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
pre[i]=i;
for(int i=0;i<m;i++){
cin>>ww[i].x>>ww[i].y>>ww[i].day;
}
sort(ww,ww+m,cmp);
int pr=-1,ans=0;
for(int i=0;i<m;i++){
int pd =union1(ww[i].x,ww[i].y);
if(pd&&pr!=ww[i].day){
ans++;
pr = ww[i].day;
}
}
cout<<ans<<endl;
return 0;
}
!!!!手误多打了个!号,数组开小了卡了我半天,,,,
总的来说:带有一点逆向思维的意思。