一个很难的程序

时间:2017-07-12 00:10:51

标签: c++ algorithm recursion

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

所以我一直在尝试这个问题3天,但我得到了一个解决方案,但是对于隐藏的测试用例来说却失败了。

问题:

每年都会举行一个乡村节日,其中有几组亲戚聚会。为每个人分配一个正整数的标识符.N对亲属标识符作为输入传递。

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

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

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

边界条件: 1&lt; = N&lt; = 100001&lt; = 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;

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

1 个答案:

答案 0 :(得分:0)

基本上,你的问题是: 给出一个图表,其中节点表示为索引,边缘表示为索引对, 给定一个代表节点的索引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,用father [i] = father [j]找到所有其他索引j。

(运行时间略有改善:将ind设置为最终值后,更新i及其父亲的父亲,依此类推至值ind)

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

由于在您的示例中缺少某些数字,您可能需要创建一些表格,将您的输入索引转换为实际使用的数字范围。但是,如果我们谈论的是一个小的最大指数,比如千分之一,那么就不会这样做。