并查集 第一题 hdoj 1213
题意 告诉你几个朋友认不认识 认识的在一桌 问有几个桌子
并查集一下 查找Find(i)==i 的个数
/*
hdoj 1213
*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <set>
using namespace std;
const int MAX_N = 1224;
int fa[MAX_N],n;
int Find(int x){
if(fa[x] == x) return x;
return fa[x] = Find(fa[x]);
}
void Merge(int a,int b){
int x = Find(a),y = Find(b);
if(x!=y){
fa[x] = y;
}
}
int main(){
int t;
int m;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
for(int i = 1;i<=n;++i)
fa[i] = i;
for(int i = 1; i<=m;++i){
int a,b;
scanf("%d%d",&a,&b);
Merge(a,b);
}
int cnt = 0;
for(int i = 1;i<=n;++i)
if(fa[i]==i) cnt++;
printf("%d\n",cnt);
}
return 0;
}
并查集第二题 POJ 1611
题意 标号为0的人会生病 和他在一起有接触的会传染 问你有多少人会被传染
我们把每一行 都连第一个父亲 然后暴力查找有多少个人的祖先和0一样 一样就是患病了
/*
POJ 1611
*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <set>
using namespace std;
#define dbg(x) ;
//cout<<#x<<" = "<< (x)<< endl
const int MAX_N = 30024;
int fa[MAX_N],n;
int arr[MAX_N];
int Find(int x){
if(fa[x]==x) return x;
return fa[x]=Find(fa[x]);
}
int Find2(){
int Count = 1,i;
for(i= 1;i<n;++i)
if(Find(0)==Find(i)) Count++;
return Count;
}
void Merge(int a,int b){
int x= Find(a),y = Find(b);
if(x!=y){
fa[x] = y;
}
}
int main(){
int m;
while(scanf("%d%d",&n,&m)&&(n||m)){
for(int i = 0;i<n;++i){
fa[i] = i;
}
for(int i = 1;i<=m;++i){
int t;
scanf("%d",&t);
for(int j = 1;j<=t;j++){
scanf("%d",arr+j);
dbg(arr[j]);
}
for(int j = 2;j<=t;++j){
Merge(arr[j-1],arr[j]);
}
}
printf("%d\n",Find2());
}
return 0;
}
并查集第三题 POJ 2236
题意 发生了地震 给你好多点坐标 和k距离以内的点可以相连
每次恢复一个点 那么他会连k距离以内的点 询问两个点是否连接
我们暴力扫一遍 连点 查询父亲是不是相同即可
/*
POJ 2236
*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <set>
using namespace std;
#define dbg(x) ;
//cout<<#x<<" = "<< (x)<< endl
const int MAX_N = 30024;
bool vis[MAX_N];
int n,fa[MAX_N];
struct node {
int l,r;
}arr[MAX_N];
int Find(int x){
if(fa[x]==x) return x;
return fa[x] = Find(fa[x]);
}
void Merge(int a,int b){
int x = Find(a),y = Find(b);
if(x!=y){
fa[x] = y;
}
}
int main(){
int d;
scanf("%d%d",&n,&d);
for(int i = 1;i<=n;++i)
scanf("%d%d",&arr[i].l,&arr[i].r);
for(int i = 1;i<=n;++i)
fa[i] = i;
char str[20];
while(scanf("%s",str)!=EOF){
if(str[0]=='O'){
int a;
scanf("%d",&a);
vis[a] = 1;
for(int i = 1;i<=n;++i){
if(i==a||!vis[i]) continue;
if(abs(arr[i].l-arr[a].l)*abs(arr[i].l-arr[a].l)+abs(arr[i].r-arr[a].r)*abs(arr[i].r-arr[a].r)<=d*d){
Merge(i,a);
}
}
}
else {
int a,b;
scanf("%d%d",&a,&b);
dbg(fa[a]);
dbg(fa[b]);
if(Find(a)==Find(b)) printf("SUCCESS\n");
else printf("FAIL\n");
}
}
return 0;
}
并查集第四题 HDOJ 3038
题意 给你好多区间的值 问你有几句话是假的
我们把所有区间的值都连起来 维护一个种类并查集 如果这个区间的值和之前出现的不一样 那么就是假的
否则更新 这里用的是 x -> fa[x] 的距离来更新 画下图可以知道关系式
/*
hdoj 3038
*/
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
using namespace std;
const int MAX_N = 200024;
int fa[MAX_N],sum[MAX_N];
int Find(int x){
if(fa[x]==x) return x;
int y = fa[x];
Find(fa[x]);
sum[x] += sum[y];
return fa[x]=Find(fa[x]);
}
int main(){
int n,m;
while(scanf("%d%d",&n,&m)!=EOF){
for(int i = 0;i<=n;++i)
fa[i] = i,sum[i] = 0;
int ans = 0;
while(m--){
int l,r,v;
scanf("%d%d%d",&l,&r,&v);
l--;
int p = Find(l);
int q = Find(r);
if(p!=q){
fa[p] = q;
sum[p] = sum[r] + v - sum[l];
}
else {
if(sum[l]-sum[r]!=v) ans++;
}
}
printf("%d\n",ans);
}
return 0;
}
并查集第五题 POJ 2492
题意 给你几个人发生了关系 发生关系的是异性
问你有没有同性 简单维护一下 可以知道带权并查集也是比较好维护的 但是自己这里实现了这种并查集 维护同性 与 异性
是同性 那就都一样 喜欢的人和同类人 flag = 1 否则更新异性
/*
POJ 2492
*/
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <sstream>
#include <stack>
#include <queue>
#define dbg(x) cout<<#x<<" = "<< (x)<< endl
using namespace std;
const int MAX_N = 10024;
int fa[MAX_N];
int Find(int x){
if(x==fa[x]) return fa[x];
return fa[x] = Find(fa[x]);
}
int main(){
int t;
scanf("%d",&t);
for(int k = 1;k<=t;++k){
printf("Scenario #%d:\n",k);
int n,m;
scanf("%d%d",&n,&m);
for(int i = 1;i<=2*n;++i)
fa[i] = i;
int flag = 0;
while(m--){
int a,b;
scanf("%d%d",&a,&b);
if(Find(a)!=Find(b)||Find(a+n)!=Find(b+n)){
fa[Find(a)] = Find(b+n);
fa[Find(a+n)] = Find(b);
}
else flag = 1;
}
if(flag) printf("Suspicious bugs found!\n");
else printf("No suspicious bugs found!\n");
printf("\n");
}
return 0;
}
并查集第六题 POJ 1703
题意 这个地方就两个帮派 给你A 问你这两个人是不是一个帮派的 给你D 告诉你这两个人不是一个帮派的
简单维护一下就好了 是一个帮派 自己和敌人一样 不是一个帮派的 自己和敌人不一样
/*
POJ 1703
*/
#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
#include <sstream>
#include <set>
#include <map>
using namespace std;
const int MAX_N = 200024;
int fa[MAX_N];
int Find(int x){
if(fa[x]==x) return x;
return fa[x] = Find(fa[x]);
}
int main(){
int t;
scanf("%d",&t);
while(t--){
int n,m;
scanf("%d%d",&n,&m);
for(int i = 1;i<=2*n;++i)
fa[i] = i;
while(m--){
int a,b;
char str[5];
scanf("%s%d%d",str,&a,&b);
if(str[0]=='A'){
if(Find(a)!=Find(b)&&Find(a)!=Find(b+n)) printf("Not sure yet.\n");
else if(Find(a)==Find(b)) printf("In the same gang.\n");
else printf("In different gangs.\n");
}
else {
if(Find(a)!=Find(b+n)){
fa[Find(a)] = Find(b+n);
fa[Find(a+n)] = Find(b);
}
}
}
}
return 0;
}
并查集第七题 HDOJ 1272
中文题意
flag 代表有没有成环 如果成环就不可以 num代表成了几个环 如果有多个环 那就不能互相走
/*
hdoj 1272
*/
#include <cstring>
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <sstream>
using namespace std;
const int MAX_N = 100024;
int fa[MAX_N] = {0};
int Find(int x){
if(fa[x]==x) return fa[x];
return fa[x] = Find(fa[x]);
}
void Merge(int a,int b){
a = Find(a);
b = Find(b);
if(a!=b)
fa[a] = b;
}
int main(){
int a,b,i,sum;
while(1){
int flag = 0;
while(scanf("%d%d",&a,&b)&&(a&&b)){
if(a==-1&&b==-1) break;
if(fa[a]==0) fa[a] = a;
if(fa[b]==0) fa[b] = b;
int p = Find(a),q = Find(b);
if(p==q){
flag = 1;
}
else Merge(a,b);
}
for(i = 1,sum = 0;i<MAX_N;i++){
if(fa[i]==i) sum++;
fa[i] = 0;
}
if(a==-1&&b==-1) break;
if(flag||sum>1) printf("No\n");//sum代表几个环 flag代表有没有成环
else printf("Yes\n");
}
return 0;
}
并查集第八题 同上一题
题意 和上一题一样吧 应该是
/*
poj 1308
*/
#include <cstring>
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <sstream>
using namespace std;
const int MAX_N = 100024;
int fa[MAX_N] = {0};
int Find(int x){
if(fa[x]==x) return fa[x];
return fa[x] = Find(fa[x]);
}
void Merge(int a,int b){
a = Find(a);
b = Find(b);
if(a!=b)
fa[a] = b;
}
int main(){
int a,b,i,sum,cnt=0;
while(1){
int flag = 0;
cnt++;
while(scanf("%d%d",&a,&b)&&(a&&b)){
if(a==-1&&b==-1) break;
if(fa[a]==0) fa[a] = a;
if(fa[b]==0) fa[b] = b;
int p = Find(a),q = Find(b);
if(p==q){
flag = 1;
}
else Merge(a,b);
}
for(i = 1,sum = 0;i<MAX_N;i++){
if(fa[i]==i) sum++;
fa[i] = 0;
}
if(a==-1&&b==-1) break;
printf("Case %d ",cnt);
if(flag||sum>1) printf("is not a tree.\n");//sum代表几个环 flag代表有没有成环
else printf("is a tree.\n");
}
return 0;
}