DisJoint_Set

//不相交集的概念(并查集) Union Find 
//disjoint set &&  set
//查找某个元素在那个集合 
//map <A B >  key - value
#include<iostream>
#include<set>
#include<map>
using namespace std;
typedef struct Disjoint_Set{
	int *data;
	int *parent;//负数利用起来 
	int capacity;
	int size;
	map<int,int>m;//
	//构造函数 
	Disjoint_Set(int max=10){
		capacity=max;
		size=0;
		//从1开始放元素 
		parent=new int[max+1];
		data=new int[max+1];
	}
	//析构函数
	~ Disjoint_Set(){
		delete[]parent;
		delete[] data;
	}
	bool insert(int x){
		if(size==capacity) return false;
		size++;
		data[size]=x;
		m[x]=size;//看成 
		parent[size]=-1;//改成表示大小为1 
		
		
		return true;
	}
	void print(){
		for(int i=1;i<=size;i++){
			cout<<i<<"\t";		
		}
		cout<<endl;
		for(int i=1;i<=size;i++){
			cout<<parent[i]<<"\t";		
		}
		cout<<endl;
		for(int i=1;i<=size;i++){
			cout<<data[i]<<"\t";		
		}
		cout<<endl;
	}
	//找x的树根的下标是多少 
	int find(int x){
		typename map<int,int>::iterator it;
		it=m.find(x);
		if(it==m.end()) return -1;
		//否则找到的话,it指向的是找到的那个键值对,不只是data 
		int i,rt;
		i=rt=it->second;
		while(parent[rt]>0)
			rt=parent[rt];
		
//路径压缩 
		int tmp;//临时变量	
		for(;i!=rt;i=tmp){
			tmp=parent[i];
			parent[i]=rt;
		}	
			
			
	
		return rt;
	} 
	//并两个数,不止是树根 
	void unionset(int x,int y){
		int rx,ry;
		rx=find(x);//树根的size 
		ry=find(y);
		
		if(rx==-1||ry==-1) return ;
		if(rx==ry) return ;
		if(parent[rx]<parent[ry]){
			parent[rx]+=parent[ry];
			parent[ry]=rx;
		}
		else{
			parent[ry]+=parent[rx];
			parent[rx]=ry;
		}	
	}
	
	
}Disjoint_Set;

int main(){
	Disjoint_Set s; 
	s.insert(11);
	s.insert(22);
	s.insert(66);
	s.insert(-5);
	s.insert(123);
	
	s.unionset(11,66);
	s.unionset(22,11);
//	s.unionset(66,-5);    
	s.print() ;

//	数据->下标->父亲  返回下标 
	 
	
	
	
	
	return 0; 
} 

下面两道题,开始是用上面自己写的代码套进去,发现不对
再看了一下题目发现 它没有插入操作,直接用数组把 size 和 data[size] 合到一起了

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e7+10;
int vis[maxn];
void init(){
	for(int i=1;i<=maxn;i++){
		vis[i]=i;
	}
}
int find(int x)
{
	if(vis[x]==x){
		return x;
	}
	else{
		vis[x]=find(vis[x]);
		return vis[x];
	}
}
void merge(int a,int b)
{
	int p=find(a);
	int q=find(b);
	if(p==q){
		return ;
	}
	else{
		if(q>p) 
			vis[q]=p;
		else
			vis[p]=q;
		return ;
	}
	return;
}
int main()
{
	int n;
	cin>>n;
	init();
	while(n--){
		int a,b,c;
		scanf("%d %d %d",&a,&b,&c);
		if(a==1){
			merge(b,c);
		}
		else if(a==2){
			if(find(b)==find(c)){
				printf("YES\n");
			}
			else{
				printf("NO\n");
			}
		}
	}
	return 0;
}

注意题目在中说的是,从1开始连续,所以在判断sum的时候,比较最大值是sum就🆗了,注意循环赋值不要错了

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e4+10;
int vis[maxn];
int fri_ans=0,sum=0,quan_ans=0;
void init(){
	for(int i=1;i<=maxn;i++){
		vis[i]=i;
	}
}
int find(int x)
{
	if(vis[x]==x){
		return x;
	}
	else{
		vis[x]=find(vis[x]);
		return vis[x];
	}
}
void merge(int a,int b)
{
	int p=find(a);
	int q=find(b);
	if(p==q){
		return ;
	}
	else{
		if(q>p) 
			vis[q]=p;
		else
			vis[p]=q;
		
		fri_ans++; 
		return ;
	}
}
int main()
{
	int n;
	cin>>n;
	init();
	while(n--){
		int i,a,b,c;
		cin>>a>>b;
		if(b>sum) sum=b;//因为不止一次,所以要判断看看要不要赋值
		for(i=0;i<a-1;i++){
			cin>>c;
			if(c>sum) sum=c;//
			merge(b,c);
		}
	}
	
	//对于基友圈的理解,总人数-好朋友的次数 
	quan_ans=sum-fri_ans;
	cout<<quan_ans<<" "<<sum<<endl;
	int k;cin>>k;
	while(k--){
		int a,b;
		cin>>a>>b;
		if(find(a)==find(b)) cout<<"Yes"<<endl;
		else cout<<"No"<<endl;
	}
	return 0;
}
这个报错是因为在使用 `multiprocessing.Pool` 进行并行处理时,锁对象 `lock` 不能直接传递给子进程。根据报错信息,锁对象只能通过继承的方式在子进程之间共享。 为了解决这个问题,你可以使用 `multiprocessing.Manager` 模块的 `Lock` 对象来创建一个可在多个进程之间共享的锁。以下是修改后的示例代码: ```python import numpy as np import multiprocessing as mp def find_connected_components(image, start_row, end_row, disjoint_set, lock): rows, cols = image.shape for i in range(start_row, end_row): for j in range(cols): if image[i, j] == 1: # 如果当前像素点是前景点 neighbors = [] if i > 0 and image[i-1, j] == 1: neighbors.append((i-1, j)) if i < rows-1 and image[i+1, j] == 1: neighbors.append((i+1, j)) if j > 0 and image[i, j-1] == 1: neighbors.append((i, j-1)) if j < cols-1 and image[i, j+1] == 1: neighbors.append((i, j+1)) if len(neighbors) == 0: # 如果当前像素点没有相邻的前景点,则创建一个新的连通分量 with lock: disjoint_set.make_set((i, j)) else: # 如果当前像素点有相邻的前景点,则将其与相邻点合并为同一连通分量 with lock: for neighbor in neighbors: disjoint_set.union((i, j), neighbor) def parallel_connected_components(image, num_processes): rows, cols = image.shape # 使用并查集数据结构来记录连通分量 disjoint_set = DisjointSet() # 创建进程池 pool = mp.Pool(processes=num_processes) # 创建锁 manager = mp.Manager() lock = manager.Lock() # 计算每个进程处理的行数 chunk_size = rows // num_processes # 分配任务给不同的进程 results = [] for i in range(num_processes): start_row = i * chunk_size end_row = start_row + chunk_size if i < num_processes-1 else rows result = pool.apply_async(find_connected_components, (image, start_row, end_row, disjoint_set, lock)) results.append(result) # 等待所有进程完成 for result in results: result.get() # 关闭进程池 pool.close() pool.join() return disjoint_set # 示例使用的并查集数据结构 class DisjointSet: def __init__(self): self.parent = {} def make_set(self, x): self.parent[x] = x def find(self, x): if self.parent[x] != x: self.parent[x] = self.find(self.parent[x]) return self.parent[x] def union(self, x, y): root_x = self.find(x) root_y = self.find(y) if root_x != root_y: self.parent[root_x] = root_y # 示例 if __name__ == '__main__': # 二值图片示例 image = np.array([[0, 1, 0, 0, 1], [1, 1, 1, 0, 0], [0, 0, 1, 1, 0], [0, 0, 0, 0, 1], [1, 0, 1, 0, 1]]) # 并行处理连通分量 num_processes = 2 disjoint_set = parallel_connected_components(image, num_processes) # 输出每个连通分量的像素点集合 connected_components = {} for pixel in disjoint_set.parent: root = disjoint_set.find(pixel) if root not in connected_components: connected_components[root] = [] connected_components[root].append(pixel) print("Connected components:") for component in connected_components.values(): print(component) ``` 通过使用 `multiprocessing.Manager` 的 `Lock` 对象,并在访问和修改 `disjoint_set` 数据结构时使用 `with lock` 块来保护共享资源的访问,可以确保并行处理过程的线程安全性。 希望这次修改能解决你遇到的问题。如果还有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值