HDU1272-小希的迷宫
快结束了放一个数一巨巨acm路线
继续刷邝斌飞并查集专题
这题不是带权并查集貌似,不管了,切他!
判断环? 出去扒拉几口盖浇饭回来就有思路了,不就是一个数有不同的pre前驱父亲,且这俩父亲指向了同一个终极根,诶不对,洛谷评分为啥为提高,这是HDU编程大赛AC人数第7的总共8个题,而且最主要的是这个多个父亲咋处理啊?
发现根据给定的数据画成有向树唯一前驱的形式,答案就是两个数的根是个相同的数且不是他们自己,不对不对,而且我发现画成有向树唯一前驱的形式第三个样例是8指向4指向2指向6指向8成环,但实际这几个数画成样例那种形式又是没问题的,好奇妙的玩意啊,问了下文心GPT样例这玩意叫图数据结构不叫树,树是每个节点最多只能有一个父节点(除了根节点没有父节点)和任意数量的子节点。
这题意可以想到的已学的思路几乎没有啊,没啥思路果断看题解
看到题解里这句话,在同一个集合就输出NO这也太简单了,提高难度?发现之前想对了,一时判断错就误以为是错的,就是两个数的根是一样的就是No
先写下吧,第一次WA了,发现要求有且仅有,即只有一个集合,反例:3 4 5 6 0 0,3和5就没路
改完又WA,md自身到自身4 4 0 0也应该No,艹,对拍发现的。
对拍代码
1 #include <iostream> 2 #include <stdlib.h> 3 #include <time.h> 4 #include<stdio.h> 5 #include<iostream> 6 #include<time.h> 7 #include <string> 8 #include <random> 9 using namespace std; 10 int a,b; 11 int main(){ 12 srand(time(0) + (unsigned long long)(new char)); 13 for(int i=1;i<=7;i++){ 14 int n = rand()%5+1; 15 int d = rand()%5+1; 16 cout<<n<<" "<<d<<endl; 17 } 18 cout<<"0 0"<<endl; 19 cout<<"-1 -1"<<endl; 20 21 }
但改完依旧WA,看了眼vjudge的“Origin”那列,大佬提醒,0 0 相当于空图,应该Yes
改完直接AC
AC代码 —— 垃圾HDU连个discuss都没有艹,但杭电的acm确实牛逼,acm届扛把子
1 //根据题意这题不会有自身指向自身和重复的情况吧,得了有也没事,照样判断 2 #include<stdio.h> 3 #include<string.h> 4 #include<iostream> 5 #define MAX 100001 6 using namespace std; 7 int pre[MAX]; 8 int num; 9 int find(int x) 10 { 11 if(x==pre[x]) 12 return x; 13 pre[x]=find(pre[x]); 14 return pre[x]; 15 } 16 //int union[MAX];//union是个关键字 17 int union_n[MAX];//确保有即能连通。初始全为0,当union_n数组里只有一个值为1的时候,即所有点都连在他上,那就证明了有,也就是只有一个集合,如果flag也为0,那就证明了仅有一条路。有且仅有。如果不止一个union_n值为1,证明啥,证明有多个集合,互不相通则肯定有集合1中的点到不了集合2中,则No 18 int flag;//确保不多即仅有一个。初始是0,任意两点之间如果多于一条路,就弄成1,flag是1则No 19 int main() 20 { 21 flag=0; 22 num=0; 23 memset(union_n,0,sizeof(union_n)); 24 int a,b; 25 for(int i=1;i<MAX;i++){//很奇怪的事,不小心写成<=,然后num也随之被赋值成MAX了 26 pre[i]=i; 27 // cout<<" "<<i<<" "<<pre[i]<<" "<<num<<endl; 28 } 29 // cout<<" "<<num<<endl; 30 while(cin>>a>>b){ 31 if(a==-1&&b==-1) 32 break; 33 if(a==0&&b==0){ 34 35 if((num==1||num==0) && flag==0) 36 cout<<"Yes"<<endl; 37 else 38 cout<<"No"<<endl; 39 for(int i=1;i<MAX;i++) 40 pre[i]=i; 41 flag=0; 42 num=0; 43 memset(union_n,0,sizeof(union_n)); 44 continue; 45 } 46 int root1=find(a); 47 int root2=find(b); 48 // if((root1==root2) && (a!=b))//a!=b保证了自身指向自身别tm给我算成多于一条路 49 if((root1==root2) )//md自身到自身也不行,对拍发现的 50 flag=1;//证明ab之间有不止一条路了,输出No 51 else{ 52 pre[root1]=root2; 53 if(union_n[root1]==1){ 54 num--; 55 union_n[root1]=0; 56 } 57 if(union_n[root2]==0){ 58 num++; 59 // cout<<"@"<<num<<endl; 60 union_n[root2]=1; 61 } 62 } 63 } 64 }
洛谷AC代码 —— 洛谷是0/1,HDU是No/Yes
1 //根据题意这题不会有自身指向自身和重复的情况吧,得了有也没事,照样判断 2 #include<stdio.h> 3 #include<string.h> 4 #include<iostream> 5 #define MAX 100001 6 using namespace std; 7 int pre[MAX]; 8 int num; 9 int find(int x) 10 { 11 if(x==pre[x]) 12 return x; 13 pre[x]=find(pre[x]); 14 return pre[x]; 15 } 16 //int union[MAX];//union是个关键字 17 int union_n[MAX];//确保有即能连通。初始全为0,当union_n数组里只有一个值为1的时候,即所有点都连在他上,那就证明了有,也就是只有一个集合,如果flag也为0,那就证明了仅有一条路。有且仅有。如果不止一个union_n值为1,证明啥,证明有多个集合,互不相通则肯定有集合1中的点到不了集合2中,则No 18 int flag;//确保不多即仅有一个。初始是0,任意两点之间如果多于一条路,就弄成1,flag是1则No 19 int main() 20 { 21 flag=0; 22 num=0; 23 memset(union_n,0,sizeof(union_n)); 24 int a,b; 25 for(int i=1;i<MAX;i++){//很奇怪的事,不小心写成<=,然后num也随之被赋值成MAX了 26 pre[i]=i; 27 // cout<<" "<<i<<" "<<pre[i]<<" "<<num<<endl; 28 } 29 // cout<<" "<<num<<endl; 30 while(cin>>a>>b){ 31 if(a==-1&&b==-1) 32 break; 33 if(a==0&&b==0){ 34 35 if((num==1||num==0) && flag==0) 36 cout<<"1"<<endl; 37 else 38 cout<<"0"<<endl; 39 for(int i=1;i<MAX;i++) 40 pre[i]=i; 41 flag=0; 42 num=0; 43 memset(union_n,0,sizeof(union_n)); 44 continue; 45 } 46 int root1=find(a); 47 int root2=find(b); 48 // if((root1==root2) && (a!=b))//a!=b保证了自身指向自身别tm给我算成多于一条路 49 if((root1==root2) )//md自身到自身也不行,对拍发现的 50 flag=1;//证明ab之间有不止一条路了,输出No 51 else{ 52 pre[root1]=root2; 53 if(union_n[root1]==1){ 54 num--; 55 union_n[root1]=0; 56 } 57 if(union_n[root2]==0){ 58 num++; 59 // cout<<"@"<<num<<endl; 60 union_n[root2]=1; 61 } 62 } 63 } 64 }
总结:
0、注意有且仅有,即除了要判断,是否给的俩数有同根(说明这组数据使得出现了多条路),还要判断是否有,题目“任意两点之间都要有路”,即集合必须为1
1、自身到自身也算不符合,应该No
2、0 0属于空图,应该Yes,不应该直接结束去判断下一组(但在洛谷没有这个,0 0输出啥都可以AC)
洛谷的食物链评分是提高,How Many Answers Are Wrong洛谷没有但我认为(所有带权并查集都)应该是提高+,这题洛谷也是提高
看看洛谷其他做法,有克鲁斯卡尔最小生成树的做法(搁置,接下来刷最小生成树专题)
又看到了个惊为天人 东西,居然用搜索做,我是一点都看不懂,好奇查了下他用的fst数据吓到我了居然是什么有限状态机,就是first和next的简写而已,大概知道了,这大佬用了个近乎自己创造的一个存图方法来搜的,其中这句“对于搜到的每一个点,遍历与其相邻的每一个点,如果该点不是当前点的父节点且已经被搜过,则这个图不是树”保证了仅有一个,“搜索后看一看是不是所有点都被搜到了”这句话保证了有。不学这种,太tm高深了仿佛天山折梅手,貌似也没啥用其他写法可以平替,学起来还费劲,纯纯大炮打蚊子。
思考:搜索专题的oil那个题,判断连通块,这个也是连通块,但由于搜索都是给你地图,有坐标,x和y加一减一就可以找到下一个点,但现在是图,没有坐标,上面这大佬的做法是自己发明了个写法,来存点的序列,顺序往下存,开个数组指向存储的数组下标,貌似是手写map?不看这个了
简单看下剩下题的百度搜索结果:
到了现在这个AC人数排序的并查集刷题量,基本不会出现本身不会看一眼搜索结果就会的题,所以不用怕看了就影响心境干扰思路,可以稍微放心大胆的搜,做个整理
AC人数:类型
51:POJ1417结合了DP(DP先搁置)
59:POJ1984带权并查集
64:POJ2912带权并查集
78:ZOJ3261逆向并查集
112:POJ1733离散化带权并查集
149:POJ1456结合了贪心DP(DP先搁置)
197:POJ2492种类并查集
207:POJ1308并查集延伸
惊了,继洛谷和鸡肋POJ-discuss后,无意间发现有个超级给力的,邝斌飞vjudge专题里“Origin”那一列也是个不错的讨论区
打算最快速度把并查集搞完,主要是想多练习几个带权并查集!!!不然到食物链那个题就结束了
###:发现刷题的思路跟做题不一样,回忆判断是否有环的时候,无意间百度到这题我直接懵逼了
###:为啥回忆最短路算法我脑袋空空啥也想不起来,百度查说SPFA是判断负环也做过正环的复杂度是O(VE),那一个点一个边,10^5个点,10^10直接爆炸,不可以最短路算法,再次证明用最短路就大材小用了徒增耗时。但并查集复杂度依旧先搁置
###:啊我思路好僵硬啊,刷并查集的时候一点都不想写刷过的其他算法搜索、最短路
###;哎这博客园的远古编辑器~~~~(>_<)~~~~