088_食物链问题(并查集)

 食物链问题:有N个动物,每个动物只能为A,B,C三种动物中的一种,已知 A吃B, B吃C, C吃A。

 现在给出K条信息,每条信息值可能为以下两种中的一种:

 1. x,y属于同一种动物;

 2. x吃y。

 要求找出这K 条信息中不正确的条数。 题源来自《挑战程序竞赛》第二版88页。

 此题使用并查集来实现应该比较方便。

 先初始化并查集,对于每一个动物x,创建三个元素:x,x+N,x+2N,分别代表x为动物 A, B, C。

 对于每一号动物,根据其可能性,可以归到如下三个集合中:

 1. x为A以及其捕食关系;如1号动物为A,2号动物也为A,(1,2浩动物属于同种) 3号动物为B(1号吃3号)

 2. x为B以及其捕食关系;

 3. x为C以及其捕食关系;

 以上三个并查集的集合,对于某一个来说,要么集合内全部成立,要么集合内全部不成立。

 对于某一条信息,根据如下方式来维护并查集:

 1. 如果x和y是同种,那么合并x-A和y-A,x-B和y-B,x-C和y-C, 即 (x,y)合并到第一个集合,(x+N,y+N)合并到第二个集合,(x+2N,y+2N)合并到第三个集合;

 2. 如果x吃y,那么合并x-A和y-B,x-B和y-C,x-C和y-A,即(x,y+N)合并到第一个集合,(x+N,y+2N)合并到第二个集合,(x+2N,y)合并到第三个集合;

 如果某个集合内的元素关系不冲突,那么这个集合就是可行的一个食物链关系。 可以看到由于我们维护集合关系的轮换性,如果第一个集合可行,那么第二,第三个集合同样可  行。同样,如果对于某一条信息,x-A的情况下在第一个集合中冲突,必有x-B在第二个集合中冲突,x-C在第三个集合中冲突。

 所以,检测冲突时只需检测x-A的情况。

 那么,如何检测冲突呢?

 1.如果遇到第一种关系,即x,y属于同种,那么冲突的话就是有x吃y或者y吃x。

 只需考虑x-A的情况,即发生了y-B,y-C的情况,具体为:(x-A,y-B)存在第一集合(x吃y已经存在),(x-A,y-C)存在第三集合(y吃x  已经存在)

 2.如果遇到第二种关系,即x吃y,那么冲突的情况就是y吃x后者x与y同种。

 同样只需考虑x-A的情况,即发生了y-A,y-C的情况,具体为(x-A,y-A)存在第一集合(x,y同种已经存在), (x-A,y-C)存在第三集合(y吃x已经存在)

 使用并查集的same方法就能做出以上判断。


//
//  088_food chain.cpp
//  changlle
//
//  Created by user on 12/30/15.
//  Copyright (c) 2015 user. All rights reserved.
//

#include <iostream>
using namespace std;

int par[500];
int _rank[500];

//初始化元素
void init(int n) {
    for (int i=0;i<n;i++) {
        par[i]=i;
        _rank[i]=0;
    }
 
 }

//查询树的根
int find(int x) {
    if (par[x]==x)
        return x;
    else
        return par[x]=find(par[x]);
   
}


//合并x,y所属的集合

void unite(int x, int y) {
    x=find(x);
    y=find(y);
    if (x==y) return;
    
    if (_rank[x]<_rank[y])
        par[x]=y;
    else {
        par[y]=x;
        if(_rank[x]==_rank[y])
            _rank[x]++;
  
    }

}
//判断x和y是否属于同一个集合
bool same(int x, int y) {
    
    return find(x)==find(y);
}

//以上为并查集的实现

int N=100;
int K=7;
int T[7]={1,2,2,2,1,2,1};
int X[7]={101,1,2,3,1,3,5};
int Y[7]={1,2,3,3,3,1,5};


int main() {
    
    init(N*3);
    int count=0;
    
    for (int i=0;i<K;i++){
        
        int t=T[i];
        int x=X[i]-1;
        int y=Y[i]-1;
        
        if (x<0 || N<=x || y<0 || N<=y){
            count++;
            continue;
        }
        
        if (t==1){ //属于同一类,只需针对x=A来进行判断
            
            if (same(x,y+N) || same(x,y+2*N))
                count++;
            
            else {
                unite(x,y);
                unite(x+N,y+N);
                unite (x+2*N, y+2*N);
            }
            
        }
        
        if (t==2) { //捕食关系,同样只需针对x=A来进行判断
            
            if (same(x,y) || same(x, y+2*N))
               count++;
            else {
                unite(x,y+N);
                unite(x+N,y+2*N);
                unite(x+2*N,y);
            }
        
        
    }
 }
    
        cout<<count<<endl;
    
    
    
    
    
    
    
    
    return 0;
}














  

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
并查集是一种用于解决集合合并与查询问题的数据结构。在食物链问题中,我们可以使用并查集来判断给定的K句话中有多少句是假话。 首先,我们需要创建一个并查集,其中每个动物都是一个节点。初始时,每个节点都是独立的集合。 然后,我们按照给定的K句话进行处理。对于每一句话,我们需要判断它是真话还是假话。 如果是第一种说法"1 X Y",表示X和Y是同类。我们可以通过将X和Y所在的集合合并来实现。即将X所在的集合的根节点指向Y所在的集合的根节点,或者将Y所在的集合的根节点指向X所在的集合的根节点。 如果是第二种说法"2 X Y",表示X吃Y。我们需要判断X和Y是否属于同一类。如果它们属于同一类,那么这句话就是假话。否则,这句话是真话。 最后,我们统计假话的总数即可。 以下是一个示例代码,演示了如何使用并查集解决食物链问题: ```python class UnionFind: def __init__(self, n): self.parent = list(range(n)) self.rank = [0] * n def find(self, x): if self.parent[x] != x: self.parent[x] = self.find(self.parent[x]) return self.parent[x] def union(self, x, y): root_x = self.find(x) root_y = self.find(y) if root_x == root_y: return if self.rank[root_x] < self.rank[root_y]: self.parent[root_x] = root_y elif self.rank[root_x] > self.rank[root_y]: self.parent[root_y] = root_x else: self.parent[root_y] = root_x self.rank[root_x] += 1 def count_false_statements(N, K, statements): uf = UnionFind(N+1) false_count = 0 for statement in statements: type, X, Y = statement if X > N or Y > N: false_count += 1 continue if type == 1: if uf.find(X) == uf.find(Y+N) or uf.find(X+N) == uf.find(Y): false_count += 1 else: uf.union(X, Y) uf.union(X+N, Y+N) uf.union(X+2*N, Y+2*N) elif type == 2: if uf.find(X) == uf.find(Y) or uf.find(X+N) == uf.find(Y): false_count += 1 else: uf.union(X, Y+N) uf.union(X+N, Y+2*N) uf.union(X+2*N, Y) return false_count N = 5 K = 7 statements = [(1, 1, 2), (2, 1, 3), (1, 2, 3), (2, 2, 4), (1, 4, 1), (1, 4, 3), (2, 4, 3)] false_count = count_false_statements(N, K, statements) print(false_count) # 输出:3 ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值