并查集比赛1

并查集比赛1

第一题:亲戚

很简单,并查集,先连接亲戚间的树并路径压缩,在判断两人是否在同一棵树上(拥有同一个根),值得注意的是,连接两树时要连接两树的根部,否则会出错。

int fa(int x)
{
	if(a[x]==x)
	{
		return x;
	}
	else
	{
		a[x]=fa(a[x]);
		return a[x];
	}
}

这是连接根部的代码。

第二题:银河英雄传说

和第一题基本相同。只需要添加一个距离就行。

if(c=='M')
{
	x=fa(x),y=fa(y);
    d[x]=s[y];
    s[y]+=s[x];
    f[x]=y;
}
else
{
    if(fa(x)!=fa(y))printf("-1\n");
	else
	{
		if(d[x]-d[y]<0)
		{
		    printf("%d\n",d[y]-d[x]-1);
		}
		else
		{
		    printf("%d\n",d[x]-d[y]-1);
		}
	}
}

这是主程序的主要部分。

第三题:食物链

这题是三题中最难的,需要依次判断三个种类,并记录下来,然后判断真假。

if(x>n||y>n)
{
	ans++;
	continue;
}
if(d==1)
{
	if(fa(x)==fa(y+n)||fa(x+n)==fa(y))
	{
		ans++;
		continue;
	}				
	f[fa(x)]=fa(y);f[fa(x+n)]=fa(y+n);f[fa(x+n+n)]=fa(y+n+n);
}
else
{
	if(fa(x)==fa(y)||fa(x)==fa(y+n))
	{
		ans++;
		continue;
	}				
	f[fa(x)]=fa(y+n+n);f[fa(x+n)]=fa(y);f[fa(x+n+n)]=fa(y+n);
}

这是判断的代码。

总结:这一套题都不算特别难,但有一些的方需要注意。如果一直都做不对,不妨认真检查、调试一次,或者重新再做一遍。最后祝大家每道题都能通过!!!~

### 并查集 C++ 实现比赛队问题 并查集是一种高效的数据结构,常用于解决动态连通性问题。对于比赛中的队问题,可以通过维护一选手之间的关系来判断哪些选手可以成团队[^1]。 以下是基于并查集C++ 实现代码: #### 初始化部分 通过 `pre` 数记录每个节点的父亲节点,初始状态下每个节点都是自身的父亲节点。 ```cpp #include <iostream> #include <vector> using namespace std; int pre[1000]; // 假设最多有1000名参赛者 // 寻找根节点,并进行路径压缩优化 int unionsearch(int x) { if (x != pre[x]) { pre[x] = unionsearch(pre[x]); // 路径压缩 } return pre[x]; } ``` #### 合并操作 定义 `join` 函数,用于将两个不同的集合合并到同一个集合中。 ```cpp void join(int root1, int root2) { int x = unionsearch(root1); int y = unionsearch(root2); if (x != y) { pre[x] = y; // 将root1所在的集合合并到root2所在集合下 } } ``` #### 主程序逻辑 假设输入为若干对朋友关系 `(u, v)`,表示编号为 `u` 和 `v` 的两名选手是朋友,则调用 `join(u, v)` 来建立他们的联系。最终统计有多少个独立的集合即可得到队伍数量。 ```cpp int main() { int n, m; cin >> n >> m; // 输入n个人和m条朋友关系 // 初始化每个人的父亲为自己 for (int i = 1; i <= n; ++i) { pre[i] = i; } // 处理每一条朋友关系 for (int i = 0; i < m; ++i) { int u, v; cin >> u >> v; join(u, v); // 如果两人是朋友,则将其加入同一集合 } // 计算总共有多少个独立的集合(即队伍) vector<int> roots; for (int i = 1; i <= n; ++i) { if (unionsearch(i) == i) { // 找到一个新集合的代表元 roots.push_back(i); } } cout << "Total teams: " << roots.size() << endl; // 输出队伍总数 return 0; } ``` 上述代码实现了基本的比赛队功能,其中利用了并查集的核心思想——快速查找与合并集合[^2]。 --- #### 进一步扩展:处理敌人关系 如果题目还涉及敌人关系(即某些人不能在同一支队伍),可以在原有基础上增加额外标记数 `enemy` 表示每个人的敌人列表,并在每次尝试合并时检查是否存在冲突[^3]。 ```cpp vector<vector<int>> enemy(1001); // 存储敌人的邻接表 bool hasConflict(int a, int b) { int pa = unionsearch(a), pb = unionsearch(b); for(auto &e : enemy[pb]){ if(e == pa){ return true; // 发生冲突 } } return false; } for (int i = 0; i < q; ++i){ // q次查询 char type; int u, v; cin >> type >> u >> v; if(type == 'F'){ // F表示朋友关系 if(!hasConflict(u, v)){ join(u, v); } }else{ // E表示敌人关系 enemy[u].push_back(v); enemy[v].push_back(u); } } ``` 此扩展版本能够更灵活地应对复杂的关系网络。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值