一个困难的程序

A program which is difficult

本文关键字:程序 一个      更新时间:2023-10-16

这是我在csstack交换中的第一篇文章,我不知道这种类型的问题是否可以在这里发布。

所以我已经尝试了这个问题 3 天,我得到了一个解决方案,但它对于隐藏的测试用例失败了。

问题:

每年都会举办一个乡村节日,几组亲戚都会见面。每个人都被分配了一个标识符,该标识符是一个正整数。N 对亲属标识符作为输入传递。

然后最后给定一个人的标识符I,程序必须打印具有标识符I的人组中亲属C的计数。

输入格式: 第一行包含 N 的值。 N 行包含两个相关人员的标识符。 下一行 (N+2( 第 1 行将包含要为其打印其组的相对计数的人员的标识符 I。

输出格式: 第一行将包含标识符为 I 的人员组中的亲属 C 计数。

边界条件: 1 <= N <= 100001 <= I <= 1000000

例 输入/输出 1: 输入:

5
10 20
30 20
40 10
55 35
55 22
40

输出:4

解释:

10、20、30、40形成一个相对组。 55、35、22形成另一个相对组。 因此,标识符为 40 的人的亲属计数为 4。

我接近的方法是:

for(auto i = v.begin() ; i!=v.end();i++)
{
if(i->first == r || i->second == r)
{
count+=2;
if(i->first == r)
r = i->second;
else
r = i->first;
remove(v.begin(),v.end(),*i);
n--;
break;
}
}
for(int i =0;i<n;i++)
{
for(int j =0;j<n;j++)
{
if(r == v[j].first || r == v[j].second)
{
if(r == v[j].first)
r = v[j].second;
else
r = v[j].first;
count++;
remove(v.begin(),v.end(),v[j]);
n--;
}
}
}
cout<<count;

那么这个问题的正确解决方案是什么?

本质上,你的问题是这样的: 给定一个节点表示为索引,边表示为索引对的图形, 并给定一个表示节点的索引 i, 查找连接到给定节点的所有节点。

UnionFind 算法,用于在具有索引的节点上查找连接的组件:

Initialize an array father of size number of nodes, with father[i] = i
for each edge e consisting of two indices i, j:
ind = i
while(ind != father[ind]) ind = father[ind]
father[j] = ind
for each entry i of the array:
replace father[i] by father[father[i]] until those are equal

之后,同一组件中的所有节点都具有相同的父节点。你用你的数据这样做,然后,对于给定的索引 i,找到所有其他索引 j,父[i] = 父[j]。

(运行时间略有改进:将 IND 设置为其最终值后,将 i 的父项及其父项等更新为值 ind(

UnionFind的简短解释:它创建一个树,其中只存储指向节点父节点的索引指针(只需要一个数组(。这是通过迭代边缘来完成的。对于每个边,其中一个事件节点的父节点设置为另一个节点的最高祖先。从本质上讲,我们从单个节点的森林开始,并将它们组装成树。最后,我们改变剩余的树,使所有叶子都是根的直接子级。

由于在您的示例中缺少一些数字,因此您可能希望创建一些表,将输入索引转换为实际使用的数字范围。但是,如果我们谈论的是一个小的最大指数,比如低于一千,不这样做并没有什么坏处。

相关文章: