两道关于并查集的题目

知识点

其实我是在刷蓝桥杯的真题的时候才发现了这个知识点,看别人题解代码看不懂,然后就去学习了一下,看了一个大佬写的并查集相关解释,简直深得我心,传送门,里面江湖大侠的例子让我顿时明白了,哈哈哈哈。
主要代码块
1.找掌门人 2.合并

int find(int k)
{
	if(f[k]==k) return k;
	return f[k]=find(f[k]);
}
void hebing(int x1,int x2)
{
	int y2=find(x2);
	int y1=find(x1);
	if(y2!=y1)
	f[y1]=y2;
}

七段码(并查集+dfs)

分析:dfs搜索出所有情况,再进行判断

#include<bits/stdc++.h>
using namespace std;
// a b c d e f g
// 1 2 3 4 5 6 7
int e[10][10];//e[i][j]表示i与j的关系,1的时候为手拉手
int use[10];//use[i]=1表示灯i亮着,0表示不亮
int f[10]; //f[i]为i的上一级,开始时默认为上一级是自己
int ans;//符合要求的方案种类 
void init()
{
	int i;
	for(i=1;i<=7;i++)
	    f[i]=i;
} 
void E()//初始化地图 
{
	
	e[1][2]=e[2][1]=1;
	e[1][6]=e[6][1]=1;
	e[2][3]=e[2][7]=1;
	e[3][2]=e[7][2]=1;
	e[3][4]=e[4][3]=1;
	e[4][5]=e[5][4]=1;
	e[5][6]=e[6][5]=1;
	e[5][7]=e[7][5]=1;
	e[6][7]=e[7][6]=1;
	e[3][7]=e[7][3]=1;
	
} 
int find(int k)//找头头 
{
	if(f[k]==k) return k;
	return f[k]=find(f[k]);
}
void hebing(int x1,int x2)
{
	//不相同就联手! 
	int y1=find(x1);
	int y2=find(x2);
	if(y1!=y2)
	f[y1]=y2;
	
}
void dfs(int n)//n为当前的灯
{
	
	if(n>7)//一组情况考虑完啦,我们来看看是不是每段都手拉手呢
	{
		init();
		int i,j;
		for(i=1;i<=7;i++)
		{
			for(j=1;j<=7;j++)
			{
				if(use[i]&&use[j]&&e[i][j])//亮着的并且手拉手的放到一起去呀
				{
					hebing(i,j);
				} 
				
			}
		}
		int l=0;
		//判断所有亮着的是不是在刚刚创建的手拉手集合里 
		//如果这些亮着的灯里面只有一个灯的头头是等于自己的,也就表示其他亮着的灯的头头就是它,表明大家共同的头头是一样的,也就是在一个集合里 
		for(i=1;i<=7;i++)
		{
			if(use[i]&&find(i)==i)
			l++;
		}
		if(l==1) ans++;
		//切记要回溯!! 
		return;
		
	} 
	 //打开当前灯,继续操作下一段灯 
	 use[n]=1;
	 dfs(n+1);
	 //关掉当前灯,继续操作下一段灯 
	 use[n]=0;
	 dfs(n+1);
 } 
int main()
{
	E();
	
	dfs(1);
	
	cout<<ans;
	
}

网络分析(并查集)

【问题描述】
小明正在做一个网络实验。
他设置了 n 台电脑,称为节点,用于收发和存储数据。
初始时,所有节点都是独立的,不存在任何连接。
小明可以通过网线将两个节点连接起来,连接后两个节点就可以互相通信
了。两个节点如果存在网线连接,称为相邻。
小明有时会测试当时的网络,他会在某个节点发送一条信息,信息会发送
到每个相邻的节点,之后这些节点又会转发到自己相邻的节点,直到所有直接
或间接相邻的节点都收到了信息。所有发送和接收的节点都会将信息存储下来。
一条信息只存储一次。
给出小明连接和测试的过程,请计算出每个节点存储信息的大小。
【输入格式】
输入的第一行包含两个整数 n,m,分别表示节点数量和操作数量。节点从
1 至 n 编号。
接下来 m 行,每行三个整数,表示一个操作。
如果操作为 1 a b,表示将节点 a 和节点 b 通过网线连接起来。当 a = b
时,表示连接了一个自环,对网络没有实质影响。
如果操作为 2 p t,表示在节点 p 上发送一条大小为 t 的信息。
【输出格式】
输出一行,包含 n 个整数,相邻整数之间用一个空格分割,依次表示进行
完上述操作后节点 1 至节点 n 上存储信息的大小。
试题J: 网络分析 12
第十一届蓝桥杯大赛软件类省赛 C/C++ 大学 B 组
【样例输入】
4 8
1 1 2
2 1 10
2 3 5
1 4 1
2 2 2
1 1 2
1 2 4
2 2 1
【样例输出】
13 13 5 3
【评测用例规模与约定】
对于 30% 的评测用例,1 ≤ n ≤ 20,1 ≤ m ≤ 100。
对于 50% 的评测用例,1 ≤ n ≤ 100,1 ≤ m ≤ 1000。
对于 70% 的评测用例,1 ≤ n ≤ 1000,1 ≤ m ≤ 10000。
对于所有评测用例,1 ≤ n ≤ 10000,1 ≤ m ≤ 100000,1 ≤ t ≤ 100。
分析:基础并查集问题啦

#include<bits/stdc++.h>
using namespace std;
int n,m;//n表示结点数量,m表示操作数量
int num[10002];//表示每个结点信息数量
int f[10002];//f[i]为i的上一级,初始时默认为自己

void init()//初始化集合
{
	int i;
	for(i=1;i<=n;i++)
	    f[i]=i;
} 
int find(int k)//找到当前元素的头头 
{
	if(f[k]==k) return k;//自己是独立集合的时候自己是头头 
	return f[k]=find(f[k]);//自己不是头头一直往上一级寻找 
}
void hebing(int x1,int x2)
{
	int y2=find(x2);
	int y1=find(x1);
	//如果他们俩的头头不是同一个头头,也就是他们俩不在一个集合里面
	if(y2!=y1)//让头头1的头头是头头2,这样它们就属于一个大家庭啦 
	f[y1]=y2;
}
int main()
{
	cin>>n>>m;
	int i,j;
	int f,a,b;
	init();
	for(i=0;i<m;i++)
	{
		cin>>f>>a>>b;
		if(f==1)//合并 
		{
			hebing(a,b);
		}
		else if(f==2)//发信息 
		{
			//把包含a的集合中每个成员的信息数量加b
			 for(j=1;j<=n;j++)
			 {
			 	//遍历所有元素,如果他们的头头和a的头头一样就能接收信息啦
				 if(find(j)==find(a))
				 num[j]+=b;
				  
			 }
			
		}
	}
	for(i=1;i<=n;i++)
	cout<<num[i]<<' ';
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值