并查集 hdu

蓝桥杯6.15训练
今日总结:
裤子给的sort模板:
https://paste.ubuntu.com/p/sJHGVctC7C/

  1. 并查集
  • hdu1232
#include<cstdio>
#include<iostream>
using namespace std;
const int maxn = 1006;
int pre[maxn];
int num = maxn;
int N,M;
void  init(){
	for(int i = 1;i <= N;i ++){
		pre[i] = i;
	} 
	num = N-1;
	return ;
}
int find(int x){
	if(x == pre[x]){
		return pre[x];
	}
	pre[x] = find(pre[x]);
	return pre[x];
}
void uniont(int start,int end){
	int x = find(start);
	int y = find(end);
	if(x != y){
		pre[x] = y;
		num --;
	}
}
int main(){
	
	while(scanf("%d",&N)){
		if (N == 0){
			break;
		}
		scanf("%d",&M);
		init();
		for(int i = 0;i < M;i ++){
			int start,end;
			scanf("%d %d",&start,&end);
			uniont(start,end);
		}
		printf("%d\n",num);
	}
}
  • 题目:hdu 5326
#include <cstdio>
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
const int maxn = 105;
int n,k;
int a,b;
int pre[maxn];
int cnt[maxn];
int ans;
void init(){
	for(int i = 1;i <= n;i ++){
		pre[i] = i;
	}
	memset(cnt,0,sizeof(cnt));
	ans = 0;
}
void creat(){
	pre[b] = a;
}
void find(int x){
	int r = x;
	while(r != pre[r]){
		
		r = pre[r];
		cnt[r] ++;
	}
}
void getans(){
	for(int i = 1;i <= n;i ++){
		if(cnt[i] == k){
			ans ++;
		}
	}
}
int main(){
	int times = 1;
	while((scanf("%d%d",&n,&k) != EOF)){
		init();
		for(int i = 0;i < n-1;i ++){	
			scanf("%d %d",&a,&b);
			creat();
		}
		for(int i = 1;i <=n;i ++){
		
			find(i);
		}
	
		getans(); 
		printf("%d\n",ans);
	}
	return 0;
} 
  • hdu 2545
    超时代码:
#include<cstdio>
#include<iostream>
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100005;
int n,m;
int a,b;
int pre[maxn];
int x,y;
void init(){
	for(int i = 1;i <= n;i ++){
		pre[i] = i;
	}
}
void creat(){
	pre[b] = a;
}
void search(int x,int y){
	int flag = 0;
	//先确认一次y是否为x的祖先:
	int r = x;
	while(r != pre[r]){
		r = pre[r];
		if(r == y){
			printf("pfz\n");
			return;
		}
	}
	r = y;
	while(r != pre[r]){
		r = pre[r];
		if(r == x){
			printf("lxh\n");
			return;
		}
	}
	//开始前进
	 while(flag == 0){
	 	x = pre[x];
	 	r = y;
		while(r != pre[r]){
			r = pre[r];
			if(r == x){
				flag = 1;
				printf("lxh\n");
				return;
			}
		}
		y = pre[y];
		int r = x;
		while(r != pre[r]){
			r = pre[r];
			if(r == y){
				flag = 1;
				printf("pfz\n");
				return;
			}
		}
	 }
	return ;
	
}
int main(){
	while(scanf("%d %d",&n,&m)){
		if((n == m)&&(n == 0)){
			break;
		}
		init();
		for(int i = 1;i <= n-1;i ++){
			scanf("%d %d",&a,&b);
			creat();
		}
		for(int i = 1;i <= m;i ++){//接下来的n次询问,查找谁会赢
			 scanf("%d %d",&x,&y);
			 search(x,y);
		}
	}
	return 0;
}

可执行代码:

#include<cstdio>
#include<iostream>
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100005;
int n,m;
int a,b;
int pre[maxn];
int x,y;
int cnt1,cnt2;//分别统计其与根节点的距离 
void init(){
	for(int i = 1;i <= n;i ++){
		pre[i] = i;
	}
	cnt1 = 0;
	cnt2 = 0;
}
void creat(){
	pre[b] = a;
}
int find(int x){
	int r = x;
	int cnt = 0;
	while(r != pre[r]){
		cnt ++;
		r = pre[r];
	}
	return cnt;
}
void search(int x,int y){
	cnt1 = find(x); 
	cnt2 = find(y);
	if(cnt1 > cnt2){
		printf("pfz\n");
	}
	else printf("lxh\n");
	return ;
	
}
int main(){
	while(scanf("%d %d",&n,&m)){
		if((n == m)&&(n == 0)){
			break;
		}
		init();
		for(int i = 1;i <= n-1;i ++){
			scanf("%d %d",&a,&b);
			creat();
		}
		for(int i = 1;i <= m;i ++){//接下来的n次询问,查找谁会赢
			 scanf("%d %d",&x,&y);
			 search(x,y);
		}
	}
	return 0;
}
  • hdu 1213
    WA代码:
#include <cstdio>
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1005;
int pre[maxn];
int n,m;
int a,b;
int cnt;

void init(){
	for(int i = 1;i <= n ;i ++){
		pre[i] = i;
	}
	cnt = 0;
}
void creat(){
	pre[b] = a;
}
void uniont(){
	for(int i = 1;i <= n;i ++){//路径压缩 
		int r = i;
		while(r != pre[r]){	
			pre[r] = pre[pre[r]];
			r = pre[r];
		}
	}
	for(int i = 0;i <= n;i ++){
		if(i == pre[i]){
			cnt ++;
		}
	} 
	cnt --;
} 
int main(){
	int t;
	scanf("%d",&t);
	while(t-- ){
		scanf("%d %d",&n,&m);
		init();
		for(int i = 1;i <= m;i ++){
			scanf("%d %d",&a,&b);
			creat();
		}
		uniont();
		printf("%d",cnt);
		
	}
} 

AC代码:

#include <cstdio>
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1005;
int pre[maxn];
int n,m;
int a,b;
int cnt;

void init(){
	for(int i = 1;i <= n ;i ++){
		pre[i] = i;
	}
	cnt = 0;
}
int find(int x){
	if(x != pre[x]){
		pre[x] = find(pre[x]);
	}
	return pre[x];
}
void creat(){
	int x,y;
	x = find(a);
	y = find(b);
	if(x != y){
		pre[y] = x;
	}
}
void uniont(){
	for(int i = 1;i <= n;i ++){
		if(find(i) == i){
			cnt ++;
		}
	} 
} 
int main(){
	int t;
	scanf("%d",&t);
	while(t-- ){
		scanf("%d %d",&n,&m);
		init();
		for(int i = 1;i <= m;i ++){
			scanf("%d %d",&a,&b);
			creat();
		}
		uniont();
		printf("%d\n",cnt);
		
	}
	return 0; 
} 
  • hdu 1856
#include <cstdio>
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100005;
int pre[maxn];
int a,b;
int stu[maxn];
int n;
void init(){
	for(int i = 1;i < maxn;i ++){
		pre[i] = i;
	}
	memset(stu,0,sizeof(stu));
}
int find(int x){
	if(pre[x] != x){
		pre[x] = find(pre[x]);
	}
	
	return pre[x];
}
void uniont(){
	int x =find(a); 
	int y = find(b);
	if(x != y){
		pre[y] = x;	
	}
	
}
int count(){
	int ans = 0;
	int k = 0;
	for(int i = 1;i < maxn;i ++){
		stu[find(i)]++;
		
	}
	
	for(int i = 1;i < maxn;i ++){
		if(find(i) == i){	
			ans = (stu[i] > ans)?stu[i]:ans;
		}
	}
	return ans;
}
int main(){
	while(scanf("%d",&n)!= EOF){
		init();
		for(int i = 1;i <= n;i ++){
			scanf("%d %d",&a,&b);
			uniont();
		}
		int ans = 0;
		ans = count(); 
		printf("%d\n",ans);
	}
}
  • hdu 3938
    tle代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <bits/stdc++.h>
using namespace std;
const int maxn =  50005;
int t;
int a,b,c;
int n,m,q;
int k1 = 0;
int city[maxn];
int k = 0;
int start = 0;
typedef struct{
	int pre;
	int v;
}Pr;
Pr pre[maxn];
typedef struct {
	int a;
	int b;//前一个连着的节点 
	int v;//权值 
}Edge;
typedef struct {
	int order;
	int req;
	int ans;
}Request;
Request re[maxn];
Edge edge[maxn];
bool cmp1(const Request &re1,const Request &re2){
 	return re1.req < re2.req;
}
bool cmp2(const Request &re1,const Request &re2){
  	return re1.order < re2.order;
}
bool cmp3(const Edge &e1,const Edge &e2){
	return e1.v < e2.v;
}
void init(){
	for(int i = 1;i <= n;i ++){
		edge[i].a = 0;
		edge[i].b = 0;
		edge[i].v = 0;
		re[i].order = i;
		re[i].req = 0;
		re[i].ans = 0;
		
		pre[i].pre = i;
		pre[i].v = maxn;
	}
	k1 = 0;	
	start = 1;
}
int find(int x){
	if(x != pre[x].pre){
		pre[x].pre = find(pre[x].pre);
	}
	return pre[x].pre;
}
void uniont(){
	int i = 0;
	for(i = start; i <= m;i ++){
		if((edge[i].v <= k)&&(edge[i].v > k1)){//表示这两个城市可达
			
			int x = find(edge[i].a);
			int y = find(edge[i].b);
			if(x != y){
				pre[x].pre = y;
				pre[y].v = edge[i].v;
			
			}
		}
		else if(edge[i].v > k){
			break;
		}
	}
	start = i;

}
int  count(){
	int ans = 0;
	for(int i = 1;i <= n;i ++){
		city[find(i)]++;
	}
	
	for(int i =1;i <= n;i ++){
		
		if((i == find(i))&&(pre[i].v <= k )){
			ans += city[i]*(city[i] -1)/2;
			
		}
	}
	return ans;
}
int main(){

	int ans;
	while(scanf("%d %d %d",&n,&m,&q)!= EOF){
		init();
		
		//读入所有边 
		for(int i = 1;i <= m;i ++){
			scanf("%d %d %d",&a,&b,&c);
			edge[i].a = a;
			edge[i].b = b;
			edge[i].v = c;
		}
		sort(edge+1,edge+m+1,cmp3);
		//读入所有请求
		for(int i = 1;i <= q;i ++){
			scanf("%d",&re[i].req);
		}
		//对所有的请求进行排序
		sort(re+1,re+q+1,cmp1);
		//debug
		
		//开始用并查集建图
		for(int i = 1;i <= q;i ++){
			
			k = 0;
			ans = 0;
			memset(city,0,sizeof(city));
			k = re[i].req;
			if(i >= 2){
				k1 =  re[i-1].req;
			}
			uniont();
			ans = count();	
			re[i].ans = ans;
		} 

		sort(re+1,re+q+1,cmp2);
		
		//将结果输出
		for(int i = 1;i <= q;i ++){
			printf("%d\n",re[i].ans);
		} 
	}
	return 0;	
}

AC代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <bits/stdc++.h>
using namespace std;
const int maxn =  50005;
int t;
int a,b,c;
int n,m,q;
// int k1 = 0;
int city[maxn];
// int k = 0;
typedef struct{
	int pre;
	int v;
    int num;
}Pr;
Pr pre[maxn];
typedef struct {
	int a;
	int b;//前一个连着的节点 
	int v;//权值 
}Edge;
typedef struct {
	int order;
	int req;
	int ans;
}Request;
Request re[maxn];
Edge edge[maxn];
bool cmp1(const Request &re1,const Request &re2){
 	return re1.req < re2.req;
}
bool cmp2(const Request &re1,const Request &re2){
  	return re1.order < re2.order;
}
bool cmp3(const Edge &e1,const Edge &e2){
	return e1.v < e2.v;
}
void init(){
	for(int i = 1;i <= n;i ++){
		pre[i].pre = i;
		pre[i].v = maxn;
        pre[i].num = 1;
	}
	// k1 = 0;	
}
int find(int x){
	if(x != pre[x].pre){
		pre[x].pre = find(pre[x].pre);
	}
	return pre[x].pre;
}
int uniont(int k,int &i){
    int ans = 0;
    for(; i <= m; i ++) {
        if(edge[i].v > k) break;
        int x = find(edge[i].a);
        int y = find(edge[i].b);
        if(x != y){
            pre[x].pre = y;
            pre[y].v = edge[i].v;
            ans += pre[x].num * pre[y].num;
            
            pre[y].num += pre[x].num;
            pre[x].num = 0;
        }
    }
    return ans;
}
// int  count(){
// 	int ans = 0;
// 	for(int i = 1;i <= n;i ++){
// 		city[find(i)]++;
// 	}
	
// 	for(int i =1;i <= n;i ++){
		
// 		if((i == find(i))&&(pre[i].v <= k )){
// 			ans += city[i]*(city[i] -1)/2;
			
// 		}
// 	}
// 	return ans;
// }
int main(){

	int ans;
	while(scanf("%d %d %d",&n,&m,&q)!= EOF){
		init();
		
		//读入所有边 
		for(int i = 1;i <= m;i ++){
			scanf("%d %d %d",&a,&b,&c);
			edge[i].a = a;
			edge[i].b = b;
			edge[i].v = c;
		}
		sort(edge+1,edge+m+1,cmp3);
		//读入所有请求
		for(int i = 1;i <= q;i ++){
			scanf("%d",&re[i].req);
            re[i].order = i;
            re[i].ans = 0;
		}
		//对所有的请求进行排序
		sort(re+1,re+q+1,cmp1);
		//debug
		
		//开始用并查集建图
        int eid = 1;
		for(int i = 1;i <= q;i ++){ 
			
			// ans = 0;
			// memset(city,0,sizeof(city));
			// k = re[i].req;
			if(i >= 2){
				// k1 =  re[i-1].req;
                re[i].ans = re[i-1].ans;
			}
			
			// ans = count();	
			re[i].ans += uniont(re[i].req,eid);
		} 

		sort(re+1,re+q+1,cmp2);
		
		//将结果输出
		for(int i = 1;i <= q;i ++){
			printf("%d\n",re[i].ans);
		} 
	}
	return 0;	
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值