ACWING/1977. 信息中继

在这里插入图片描述

输入样例:
5
0
4
1
5
4
输出样例:
2
样例解释
奶牛 1 不发送任何信息,因此不会陷入循环。

奶牛 3 发送信息给奶牛 1,因此也不会陷入循环。

其他三头奶牛发送的信息都会陷入循环。

并查集 解法

利用并查集做(并查集的同一集合特性,子节点更新都指向根节点降低查找复杂度)

因为每个牛只能单项传播,故能够成一个或多个图,若一个图中存在循环,则此图中所有牛都会陷入循环,否则一定为一棵树
因此可以利用并查集的特性解决

  • 并查集中若当前集合不存在循环,则所有点的根节点一定为0的子节点
  • 若并查集的此集合中存在循环图,则一定能根找到自己,每一次找到根就直接将自己指向根节点(如此缩短并查集判断的复杂度)
  • (注意由于每个牛最多传递一个牛,故一个图中最多一个循环环)
  • 因此在找到循环的根节点后,根节点应该是指向自己的,记录下后指向0变为树(此树都存在循环)
#include <stdio.h>
#include <iostream>
#include <vector>
#include <algorithm>
#include <string.h>

using namespace std;

int main(){
	int n;
	cin>>n;
	int arr[n+1] = {0}; // 存储当前牛的祖辈节点,初始化每个牛都为根节点
	vector<int> loop; // 存储循环并查集的root
	for(int i = 1; i <= n; i++){
		// 若当前节点为根节点,则父节点是0
		// 每次记录祖宗节点都循环找到根节点记录下来
		// 若找到祖宗节点为自己,则设自己为根,并记录到循环数组中
		cin>>arr[i];
		if(arr[i]){ // 当前节点非根节点
			while(arr[arr[i]]){
				arr[i] = arr[arr[i]]; // 直到找到爷爷节点为0,则父节点为根节点
				if(i == arr[i]){
					loop.push_back(i);
					arr[i] = 0; // 改变根,恢复为正常树,此树
					break;
				}
			}
		}
	}
	int ans = loop.size(); // 3个根节点
	for(int i = 0;i<loop.size();i++){
// 		cout<<loop[i]<<" ";
		for(int j = 1;j<=n;j++){
			while(arr[arr[j]] and arr[j] != loop[i]){
				arr[j] = arr[arr[j]];
			}
			if(arr[j] == loop[i]){
				ans++;
				// cout<<j<<" ";
			}
		}
// 		cout<<endl;
	}
	cout<<n-ans<<endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AlwaysDayOne

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值