【问题标题】:How do I solve this using union-find algorithm?如何使用联合查找算法解决这个问题?
【发布时间】:2015-11-15 07:16:25
【问题描述】:

问题:http://codeforces.com/contest/468/problem/B

小 X 有 n 个不同的整数:p1, p2, ..., pn。他想把它们都分成两组A和B。必须满足以下两个条件:

如果数字 x 属于集合 A,那么数字 a - x 也必须属于集合 A。 如果数字 x 属于集合 B,则数字 b - x 也必须属于集合 B。 帮助小 X 将数字分成两组或确定这是不可能的。

输入 第一行包含三个空格分隔的整数 n, a, b (1 ≤ n ≤ 105; 1 ≤ a, b ≤ 109)。下一行包含 n 个以空格分隔的不同整数 p1, p2, ..., pn (1 ≤ pi ≤ 109)。

输出 如果有办法将数字分成两组,则在第一行打印“YES”。然后打印 n 个整数:b1, b2, ..., bn(bi 等于 0 或 1),描述除法。如果bi等于0,则pi属于集合A,否则属于集合B。

如果不可能,打印“NO”(不带引号)。

现在,我开发了以下代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>

using namespace std;

int n,a,b,id;
int p[100100];
set<int> st;
map<int,int> mp;

int fa[100100];

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

void Bing(int a,int b)
{
    int A=find(a),B=find(b);
    if(A==B) return ;
    fa[B]=A;
}

int main()
{
    scanf("%d%d%d",&n,&a,&b);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",p+i);
        st.insert(p[i]);
        mp[p[i]]=++id;
        fa[i]=i;
    }
    fa[n+1]=n+1;///A
    fa[n+2]=n+2;///B

    for(int i=1;i<=n;i++)
    {
        int x=p[i];
        int flag = 0;
        if(st.count(a-x))
        {
            Bing(mp[x],mp[a-x]);
            flag = 1;
        }
        else
        {
            Bing(n+1,mp[x]);
            flag = 1;
        }
        if(st.count(b-x) && flag == 0)
        {
            Bing(mp[x],mp[b-x]);
        }
        else if (flag == 0)
        {
            Bing(n+2,mp[x]);
        }
    }

    if(find(n+1)==find(n+2))
    {
        puts("NO");
    }
    else
    {
        puts("YES");
        for(int i=1;i<=n;i++)
        {
            printf("%d ",find(i)==find(n+1));
        }
        putchar(10);
    }

    return 0;
}

基本上,尝试将集合A或集合B中的每个元素合并。如果它们都依次合并,则最后输出NO。但是,这给出了错误的输入答案:

3 3 4
1 2 4

输出应该是:NO 而我的代码输出为

YES
0 0 1 

我的逻辑哪里出错了?请帮忙!

【问题讨论】:

  • 也许我不明白这个问题,但看起来它给出了正确的答案。如果12都属于A,那么3-1=23-2=1也属于,44-4=0都可以属于集合B。或者减法的结果也需要适应范围吗?
  • 减法的结果也需要在范围内,是的。
  • 我说这段代码完全有效,因为规则只指定输入必须符合该范围。但是,如果您的代码有 cmets,或者以某种方式进行了解释,这将有所帮助。我不知道您是否专门检查该条件,但我猜该程序认为0 是一个有效结果。
  • 所以让我与其他评论者分享我的理解:A 和 B 没有数字范围。所以给定 a = 3 和 p1 = 2,问题不在于 3-2=1符合范围,但输入数字中是否确实存在 p_i=1。

标签: c++ arrays algorithm union-find


【解决方案1】:

考虑以下情况,P 是所有输入数字 p[i] 的集合:

  1. 有一个数字n1 in P 满足n1 = a - p[i],但没有一个数字n2 in P 满足n2 = b - p[i]
  2. 有一个数字n1 in P 满足n1 = b - p[i] 但没有一个数字n2 in P 满足n2 = a - p[i]
  3. 没有满足n = a - p[i]n = b - p[i]的号码n in P
  4. 有一个数字n1 in P 满足n1 = a - p[i] 和一个数字n2 in P 满足n2 = b - p[i]

如果您遇到情况 3. 或 4. 您想要报告失败(“否”),无论其他情况如何。

如果所有数字p[i]都属于情况1.或2.结果应该是有效的。

您应该逐行检查您的代码,如果它与此处提供的案例兼容。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-15
    • 2011-03-20
    • 2020-03-27
    • 2021-06-19
    • 2021-06-14
    • 1970-01-01
    • 2017-06-15
    • 1970-01-01
    相关资源
    最近更新 更多