POJ1182食物链带权重并查集

http://poj.org/problem?id=1182

开三种情况

1-n表示同类

1+n-n+n表示吃谁

2n+1-3n表示被谁吃

d=1

只需要判断

1、b和吃c的

2、b和被c吃的

看他们若同属一并查集就为假

此时需要合并的是

1、吃b的和吃c的

2、被b吃的和被c吃的

3、c和b

d=2

只需要判断

1、c和b吃的

2、c和b 

此时需要合并的是

1、b和吃c的

2、被b吃的和c

3、吃b的和c吃的

#include<cstdio>
using namespace std;
const int maxn = 5e4 + 5;
int n, k;
int a, b, c;
int ans = 0;
int aaa1, bbb1, aaa2, bbb2, aaa3, bbb3;  // 分别对应的三个祖先
int fa[150005];		//  三倍大的数组
inline int find(int t)   //   标准找爸爸操作
{
    if(fa[t] == t)	return t;
    return fa[t] = find(fa[t]);
}
inline void workk_same()
{
    aaa1 = find(b);
    bbb1 = find(c);
    aaa2 = find(b + n);
    bbb2 = find(c + n);
    aaa3 = find(b + 2 * n);
    bbb3 = find(c + 2 * n);
    // 直接找出三个老祖宗
    if(aaa1 == bbb2  || aaa1 == bbb3)
    {
        ans++;
        return;
    }
    // 判定有没有符合要求
    fa[aaa1] = bbb1;
    fa[aaa2] = bbb2;
    fa[aaa3] = bbb3;
    //   合并
}
inline void workk_b_eat_c()
{
    if(b == c)
    {
        ans++;
        return;
    }//下面表示b吃c;
    aaa1 = find(b);
    bbb1 = find(c);//同类
    aaa2 = find(b + n);
    bbb2 = find(c + n);//吃谁
    aaa3 = find(b + 2 * n);
    bbb3 = find(c + 2 * n);//被谁吃
    if(aaa1 == bbb1 || aaa1 == bbb2 || aaa2 == bbb3 || aaa2 == bbb2 || aaa3 == bbb3 || aaa3 == bbb1)
    {//几种
        ans++;
        return;
    }				//  判定是否合理
    fa[aaa1] = bbb3;
    fa[aaa2] = bbb1;
    fa[aaa3] = bbb2;    //  合并
}
int main()
{
    scanf("%d%d", &n, &k);
    for(int i = 1; i <= 3*n; ++i)
        fa[i] = i;
    for(int i = 1; i <= k; ++i)
    {
        scanf("%d%d%d", &a, &b, &c);
        if(b > n || c > n)
        {
            ans++;
            continue;
        }
        if(a == 1)	workk_same();
        else workk_b_eat_c();
    }
    printf("%d", ans);
    return 0;	
}

也可以优化为

#include<cstdio>
using namespace std;
const int maxn = 5e4 + 5;
int n, k;
int a, b, c;
int ans = 0;
int aaa1, bbb1, aaa2, bbb2, aaa3, bbb3;  // 分别对应的三个祖先
int fa[150005];		//  三倍大的数组
inline int find(int t)   //   标准找爸爸操作
{
    if(fa[t] == t)	return t;
    return fa[t] = find(fa[t]);
}
inline void workk_same()
{
    aaa1 = find(b);
    bbb1 = find(c);
    aaa2 = find(b + n);
    bbb2 = find(c + n);
    aaa3 = find(b + 2 * n);
    bbb3 = find(c + 2 * n);
    // 直接找出三个老祖宗
    if(aaa1 == bbb2  || aaa1 == bbb3)
    {
        ans++;
        return;
    }
    // 判定有没有符合要求
    fa[aaa1] = bbb1;
    fa[aaa2] = bbb2;
    fa[aaa3] = bbb3;
    //   合并
}
inline void workk_b_eat_c()
{
    if(b == c)
    {
        ans++;
        return;
    }//表示b吃;
    aaa1 = find(b);
    bbb1 = find(c);//同类
    aaa2 = find(b + n);
    bbb2 = find(c + n);//吃谁
    aaa3 = find(b + 2 * n);
    bbb3 = find(c + 2 * n);//被谁吃
    if(aaa1 == bbb1 || aaa1 == bbb2 )
    {//如果bc是同类、
        ans++;
        return;
    }				//  判定是否合理
    fa[aaa1] = bbb3;
    fa[aaa2] = bbb1;
    fa[aaa3] = bbb2;    //  合并
}
int main()
{
    scanf("%d%d", &n, &k);
    for(int i = 1; i <= 3*n; ++i)
        fa[i] = i;
    for(int i = 1; i <= k; ++i)
    {
        scanf("%d%d%d", &a, &b, &c);
        if(b > n || c > n)
        {
            ans++;
            continue;
        }
        if(a == 1)	workk_same();
        else workk_b_eat_c();
    }
    printf("%d", ans);
    return 0;	//  程序再见!
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值