并查集学习入门到熟悉
2016-08-07 15:49
387 查看
我的:
并查集就是把具有相同属性的一些事物归为一类,然后归类之后后就相当于形成了多个联通块,其中要注意的是pre数组记录的是他的上级,然而不一定是他的最上级,判断他是不是最上级的话就是他的pre值是不是等于该数本身,即pre[i] == i,其实有多少个最上级就相当于有多少个连通块。然而想要找到某个数的最上级是哪个数的话就是调用finds函数。finds函数里面有一个状态压缩算法,就是找到他的最上级之后,就把他和他的上几级的pre标为他们的最上级,对之后的操作很有帮助。
这个可以参考:http://blog.csdn.net/dellaserss/article/details/7724401,感觉讲的挺好的。
接下来把并查集的一些写的题贴出来吧,并查集不难的。
UVA10608 Friends
这个就是相当于求连通块了,
我的:题意是要找到最多有多少人在同一个集合里面
L2-010. 排座位
这个题就是就是一个连通块,因为朋友的朋友是朋友,而其他的如果没有给出的话就没有必然的联系,就是看他们是不是在一个朋友圈里面了,
之后的判断的敌人的话,就看有没有出现过就可以了。
PAT L2-007. 家庭房产
这个题的预处理有点麻烦,需要把变量的一些值(housenum,area)记录下来,还是有点难度的,表示调了很久,不过到了并查集这块就很简单了。
我的:
POj1611 Suspect
这个题目的意思是0号是感染源,跟感染源在同一个集合里面的话就是suspect,跟suspect在同一个集合里的话也是suspect,就是要求有多少个suspect。
求与0 在同一个连通块的个数,
我的:
并查集就是把具有相同属性的一些事物归为一类,然后归类之后后就相当于形成了多个联通块,其中要注意的是pre数组记录的是他的上级,然而不一定是他的最上级,判断他是不是最上级的话就是他的pre值是不是等于该数本身,即pre[i] == i,其实有多少个最上级就相当于有多少个连通块。然而想要找到某个数的最上级是哪个数的话就是调用finds函数。finds函数里面有一个状态压缩算法,就是找到他的最上级之后,就把他和他的上几级的pre标为他们的最上级,对之后的操作很有帮助。
这个可以参考:http://blog.csdn.net/dellaserss/article/details/7724401,感觉讲的挺好的。
接下来把并查集的一些写的题贴出来吧,并查集不难的。
UVA10608 Friends
这个就是相当于求连通块了,
我的:题意是要找到最多有多少人在同一个集合里面
#include<bits/stdc++.h> using namespace std; const int maxn=300000+10; int pre[maxn]; int num[maxn]; int n,m; void Init()//初始化 { for(int i= 1 ;i <= n;i++) { pre[i]=i; num[i]=1; } } int finds(int x) { int r=x; while(r != pre[r]) { r=pre[r]; } int i=x,j; while(i != r) { j=pre[i]; pre[i]=r; i=j; } return r; } void join(int x,int y) { int fx=finds(x),fy=finds(y); if(fx != fy){ pre[fx]=fy; num[fy]+=num[fx]; } } int main() { int Tcase; scanf("%d",&Tcase); for(int ii =1;ii <= Tcase ;ii ++) { scanf("%d%d",&n,&m); Init(); for(int i=1; i<= m; i++) { int x,y; scanf("%d%d",&x,&y); join(x,y); } int ans=0; for(int i=1;i <= n;i++){ if(num[i]>ans) ans= num[i]; } printf("%d\n",ans); } return 0; }
L2-010. 排座位
这个题就是就是一个连通块,因为朋友的朋友是朋友,而其他的如果没有给出的话就没有必然的联系,就是看他们是不是在一个朋友圈里面了,
之后的判断的敌人的话,就看有没有出现过就可以了。
#include<iostream> #include<cstring> #include<cstdio> #include<map> using namespace std; const int maxn=100000+10; int n,m; int pre[maxn]; void Init() { for(int i=1 ;i <= n;i++) { pre[i]=i; } } int finds(int x) { int r=x; while(r != pre[r]) { r=pre[r]; } int i=x,j; while(i != r) { j=pre[i]; pre[i]=r; i=j; } return r; } void join(int x,int y) { int fx=finds(x),fy=finds(y); if(fx != fy) { pre[fx]=fy; } } int main() { int s; scanf("%d%d%d",&n,&m,&s); Init(); int a[maxn][2]; int k=0; for(int ii=1;ii <= m;ii++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); if(z==1)//z==1代表的是朋友,就进行合并 join(x,y); else//代表是敌人,记录下来,之后再进行判断 { a[k][0]=x; a[k++][1]=y; } } for(int ii=1;ii <= s;ii++) { int x,y; scanf("%d%d",&x,&y); int flag1=0,flag2=0; if(finds(x)==finds(y)) flag1=1; for(int i=0;i<k;i++) { if((a[i][0]==x&&a[i][1]==y) || (a[i][0]==y&&a[i][1]==x)) {flag2=1;break;} } if(flag1 && ! flag2) cout<<"No problem"<<endl; else if(flag1 && flag2) cout<<"OK but..."<<endl; else if(!flag1 && flag2) cout<<"No way"<<endl; else if(!flag1 && !flag2) { cout<<"OK"<<endl; } } return 0; }
PAT L2-007. 家庭房产
这个题的预处理有点麻烦,需要把变量的一些值(housenum,area)记录下来,还是有点难度的,表示调了很久,不过到了并查集这块就很简单了。
我的:
#include<iostream> #include<cstring> #include<cstdio> #include<map> #include<cmath> #include<algorithm> #include<cstdlib> using namespace std; const int maxn=1000+10; struct Node { int data; int pre; int num; double housenum; double area; }nod[maxn*maxn/10],ans[maxn*maxn/10]; void Init() { for(int i=0 ;i < 10000;i++) { nod[i].pre=i; nod[i].data=i; nod[i].num=1; nod[i].housenum=0; nod[i].area=0; } } int finds(int x) { int r=x; while(r != nod[r].pre) { r=nod[r].pre; } int i=x,j; while(i != r) { j=nod[r].pre; nod[r].pre=r; i=j; } return r; } void join(int x,int y) { int fx=finds(x),fy=finds(y); if(fx != fy) { if(fx<fy)//小的最为上级,为了最后最小的是最上级 { nod[fy].pre=fx; nod[fx].num+=nod[fy].num; nod[fx].housenum+=nod[fy].housenum; nod[fx].area+=nod[fy].area; } else { nod[fx].pre=fy; nod[fy].num+=nod[fx].num; nod[fy].housenum+=nod[fx].housenum; nod[fy].area+=nod[fx].area; } } } bool comp(struct Node a,struct Node b)//最后结果的比较 { if(fabs(a.area-b.area)<(1e-7)) return a.data<b.data; return a.area>b.area; } void output(int x)//因为在处理的时候当成了整数,为了使各个数是4位输出, { if(x>=1000) cout<<x<<" "; else if(x>=100) cout<<"0"<<x<<" "; else if(x>=10) cout<<"00"<<x<<" "; else if(x>=0) cout<<"000"<<x<<" "; } int m[maxn][maxn],parents[maxn][maxn],x[maxn]; int main() { int n; scanf("%d",&n); Init(); bool flag[maxn*maxn/10]; memset(flag,false,sizeof(flag)); for(int i=0 ;i < n;i++) { double y; double z; scanf("%d",&x[i]); flag[x[i]]=true; scanf("%d%d",&parents[i][0],&parents[i][1]); // cout<<parents[i][0]<<" "<<parents[i][1]<<" "; flag[parents[i][0]]=true; flag[parents[i][1]]=true; scanf("%d",&m[i][0]); // cout<<x[i]<<" "<<parents[i][0]<<" "<<parents[i][1]<<" "<<m[i][0]<<" "<<"washdgsudfs"<<endl; for(int j=1;j<=m[i][0];j++) { // cout<<m[i][0]<<endl; scanf("%d",&m[i][j]); // cout<<m[i][j]<<" "; flag[m[i][j]] = true; } scanf("%lf%lf",&y,&z); nod[x[i]].housenum+=y; nod[x[i]].area+=z; } // for(int i=0;i<n;i++) // { // cout<<x[i]<<" "<<parents[i][0]<<" "<<parents[i][1]<<" "<<m[i][0]; // for(int j=1;j<=m[i][0];j++) // cout<<m[i][j]<<" "; // cout<<nod[x[i]].housenum<<" "<<nod[x[i]].area<<endl; // } for(int i=0;i<n;i++) { if(parents[i][0]!= -1) join(x[i],parents[i][0]); if(parents[i][1] != -1) join(x[i],parents[i][1]); for(int j=1;j<=m[i][0];j++) join(x[i],m[i][j]); } // for(int i=0;i<n;i++) // { // cout<<x[i]<<" "<<parents[i][0]<<" "<<parents[i][1]<<" "<<m[i][0]; // for(int j=1;j<=m[i][0];j++) // cout<<m[i][j]<<" "; // cout<<nod[x[i]].housenum<<" "<<nod[x[i]].area<<endl; // } int k=0; for(int i = 0; i <= 10000;i++)//找到最上级,然后复制到ans之中 { // cout<<i<<" "<<flag[i]<<" "<<nod[i].pre<<endl; if(flag[i] && nod[i].pre == i) { ans[k].num=nod[i].num; ans[k].data=nod[i].data; ans[k].area=nod[i].area/ans[k].num; ans[k].housenum=nod[i].housenum/ans[k].num; k++; } } sort(ans,ans+k,comp);cout<<k<<endl; for(int i=0;i<k;i++) { output(ans[i].data); cout<<ans[i].num<<" "; printf("%.3lf %.3lf\n",ans[i].housenum,ans[i].area); } return 0; }
POj1611 Suspect
这个题目的意思是0号是感染源,跟感染源在同一个集合里面的话就是suspect,跟suspect在同一个集合里的话也是suspect,就是要求有多少个suspect。
求与0 在同一个连通块的个数,
我的:
#include<iostream> #include<cstring> #include<cstdio> #include<map> using namespace std; const int maxn=100000+10; int n,m; int pre[maxn]; int num[maxn]; void Init() { for(int i=0;i<n;i++) { pre[i]=i; num[i]=1; } } int finds(int x) { int r=x; while(r != pre[r]) { r=pre[r]; } int i=x,j; while(i != r) { j=pre[i]; pre[i]=r; i=j; } return r; } void join(int x,int y) { int fx=finds(x),fy=finds(y); if(fx != fy) { pre[fx]=fy; num[fy]+=num[fx]; } } int main() { while(scanf("%d%d",&n,&m) != EOF && (n || m)) { int x,y,z; Init(); for(int i=0;i<m;i++) { scanf("%d%d",&x,&y); for(int j=0;j<x-1;j++) { scanf("%d",&z); join(y,z); } } int ans=num[finds(0)];与0在同一个连通块之中,0的最上级是finds(0),这个集合的个数就是num[finds(0)] cout<<ans<<endl; } return 0; }
相关文章推荐
- Bayes++ Library入门学习之熟悉class-Importance_resampler
- Bayes++ Library入门学习之熟悉UKF相关类
- Bayes++ Library入门学习之熟悉namespace
- 快速入门过程与方法:设计与思路;如何学习新的知识框架,建立思维模式,熟悉应用场景体系
- Bayes++ Library入门学习之熟悉class-Bayesian_filter_base(2)
- SpringBoot学习:从入门到熟悉
- Bayes++ Library入门学习之熟悉class-Bayesian_filter_base(1)
- 算法模板学习专栏之并查集(一)入门
- Java学习从入门到精通
- java入门学习指导之最佳方向
- [转载]Java学习从入门到精通
- XML轻松学习手册(1)XML快速入门
- Java学习从入门到精通
- Struts学习傻瓜式入门篇
- Java学习从入门到精通
- Java学习从入门到精通
- 路在何方:JAVA入门学习指导方向
- Java学习从入门到精通[转]
- Python学习足迹(4)(入门篇终结)
- Struts学习傻瓜式入门篇