题意 : 中文题就不说题意了……

分析 : 通过普通并查集的整理归类, 能够单纯地知道某些元素是否在同一个集合内。但是题目不仅只有种类之分, 还有种类之间的关系, 即同类以及吃与被吃, 而且重点是题目问的并不是种类是否在一个集合内, 而是考察给出的关系是否矛盾。在解释之前, 先明白一个问题, 对于给出的关系, 如果我不能通过前面的信息来推断出来, 是不是不能够判断现在给出关系的对错?那就将这个信息作为真命题并存储起来, 方便后面判断。有了刚刚前面的陈述, 可以知道两个东西=>

对于这个题目并查集存储的是关系(即同类或吃与被吃) && 只有能够相互之间确立关系的才能合并同一个集合内 

那如何使用并查集存储关系呢?题目给出的是两个物种和它们间的关系, 我们可以将给出 的两个物种看成两个并查集的节点, 然后将连接两个节点的边带上相应的权值代表这两个节点之间的关系, 为了通俗和具体一点, 就举例说明, 例如题目给出 1 1 2 (即1和2是同类), 存储步骤以及图示如下

①用一个father数组来存储并查集内的父子关系, 这里用father[1] = 2将1设置为2的父节点。(常规并查集操作)

②用relation数组存储连接这两个点的权值(即关系)relation[1]=x, 这里的x需要进行定义, 这里定义如下 0=>同类、1=>父节点吃子节点、2=>子节点吃夫节点(这样的定义并非随意, 后面绿色文字有说明), 所以刚刚的式子就应该是relation[1]=0。

③知道了单独两个物种的关系, 那这两个物种就属于一个集合了。但是1和2有可能并非是单独的物种, 换句话说就是1和2在合并之前可能就已经属于某一个集合了, 刚刚前面也说到, 一旦在一个集合里面, 那这个集合里面的所有元素都能互相确立关系, 那1和2能够确定关系, 那原来1所在的集合肯定也能和2原来所在的集合之间所有的元素确立关系, 所以这两个集合需要合并!

④也就像刚刚③所说, 1和2有可能并非只是单独个体, 有可能已经和其他元素构成集合, 在合并的过程中, 还需要进行路径压缩才能发挥并查集的高效!

如果做完刚刚说的步骤, 那在每一次给出的关系就能通过并查集的查找来知道这句话是否有错!但是很明显, 因为有了权值的设置, 要进行③的集合合并和④的路径压缩就要同时考虑将relation数组进行相应的变化, 因为relation[k]记录的只是k与父节点的关系, 如果进行了路径压缩, 那relation[k]就要变成k与k所在集合根节点的关系了。接下来就是用到向量的地方了!以下来说说如何使用向量知识, 进行集合合并和路径压缩

集合合并:

如果输入=>R fir sec(fir物种和sec物种有R这种关系), 那我们可以得到的已知条件是 fir 和 sec 所在集合的根节点(假设已经经过路径压缩) Fir_root 和 Sec_root, 假设我们将Sec_root接到Fir_root上, 那就能得到如下图, 则我们所要求的就是红色箭头所指代的relation, 然后将节点进行常规的并查集合并, 就能完成集合合并操作了, 也就是relation[Sec_root] = (relation[fir]+(R-1)-relation[sec]+3)%3, father[sec_root] = fir_root, 这里再说明一下relation计算的式子, %3的原因是要保证值在0~2之间, 由于有-relation[sec]操作, 所以为了避免relation[sec]过大, 使得整条模三的式子为负数, 所以进行+3操作!这里需要注意的是, R只是题目的输入(即1或2), 而我们刚刚定义的relation的取值x只有三种情况, 两者的关系是什么呢?也就是如何用输入的R得到实际我们定义的x?如果输入R=1, 对应的x=0, 而R=2, 对应的x=1, 所以x = R-1就是当前物种fir和sec的关系, 这也就是刚刚说为什么x的那三个值并非随意定义的原因。

路径压缩:

操作呢, 就如下图所示, 可见除了根节点自己所有的节点最后的父亲都是根节点, 同样的, relation的更新也可以采用向量的知识, 代码就是可以先通过递归找到根结点, 然后代码中递归的过程就是下图①~④的过程, 是从根到末尾节点的更新, 具体看代码思考

至此就完成了所有操作, 只要在操作之前判断语句是否和之前给出的关系有矛盾, 具体的还是可以用向量来思考。

留下了递归进行路径压缩中如何变relation 和 判断是否是错误语句这两个问题, 看代码即可, 相信这个是不难思考的!

#include<stdio.h>
#include<iostream>
using namespace std;
;
int father[maxn], relation[maxn], n, k, nCase;
int findset(int x)//递归寻找根节点
{
    if(x == father[x]) return x;
    int temp = father[x];//temp == x的父节点
    father[x] = findset(temp);//继续寻找根节点
    relation[x] = ( relation[temp] + relation[x] )%;//通过向量相加可以得出现在x与根节点的关系
    return father[x];
}
int main(void)£¬
{
    scanf("%d %d", &n, &k);
    ; i<=n; i++){
        father[i] = i;
        relation[i] = ;
    }
    ;
    while(k--){
        scanf("%d %d %d", &command, &fir, &sec);
         || sec<= || fir>n || sec>n) ans++;
         && fir==sec) ans++;
        else{
            int Fir_root = findset(fir);
            int Sec_root = findset(sec);
            if(Fir_root != Sec_root){//如果两个物种并不在一个关系, 也就是无法知道关系, 则合并
                father[Sec_root] = Fir_root;
                relation[Sec_root] = (  + (command - ) + relation[fir] - relation[sec] )%;
            }else{
                ) {if(relation[fir] != relation[sec]) ans++;}//如果1就代表同类, 则fir和sec与根的关系应该是一样的
                 - relation[fir] + relation[sec])% != command- ) ans++;}//如果2就代表fir吃sec即command-1, 左边式子同样根据向量运算得到
            }
        }
    }
    printf("%d\n", ans);
    ;
}

POJ 1182 食物链 (带权并查集 && 向量偏移)的更多相关文章

  1. poj 1182 食物链 带权并查集

    食物链是并查集的进阶运用的一道非常经典的题目. 题目如下: 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A, ...

  2. POJ 2492 A Bug's Life (带权并查集 && 向量偏移)

    题意 : 给你 n 只虫且性别只有公母, 接下来给出 m 个关系, 这 m 个关系中都是代表这两只虫能够交配, 就是默认异性, 问你在给出的关系中有没有与异性交配这一事实相反的, 即同性之间给出了交配 ...

  3. K - Find them, Catch them POJ - 1703 (带权并查集)

    题目链接: K - Find them, Catch them POJ - 1703 题目大意:警方决定捣毁两大犯罪团伙:龙帮和蛇帮,显然一个帮派至少有一人.该城有N个罪犯,编号从1至N(N<= ...

  4. POJ - 2912 Rochambeau (带权并查集+枚举)

    题意:有N个人被分为了三组,其中有一个人是开了挂的.同组的人的关系是‘=’,不同组的人关系是‘<’或'>',但是开了挂的人可以给出自己和他人任意的关系.现在要根据M条关系找出这个开了挂的人 ...

  5. A Bug's Life POJ - 2492 (带权并查集)

    A Bug's Life POJ - 2492 Background Professor Hopper is researching the sexual behavior of a rare spe ...

  6. poj1182 食物链 带权并查集

    题目传送门 题目大意:大家都懂. 思路: 今天给实验室的学弟学妹们讲的带权并查集,本来不想细讲的,但是被学弟学妹们的态度感动了,所以写了一下这个博客,思想在今天白天已经讲过了,所以直接上代码. 首先, ...

  7. POJ 1182 食物链(经典带权并查集 向量思维模式 很重要)

    传送门: http://poj.org/problem?id=1182 食物链 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: ...

  8. poj 1182:食物链(种类并查集,食物链问题)

    食物链 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 44168   Accepted: 12878 Description ...

  9. POJ 1182 食物链(种类并查集)

    食物链 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 63592   Accepted: 18670 Description ...

随机推荐

  1. 查找两个有序数组中的第K个元素(find kth smallest element in 2 sorted arrays)

    查找两个有序数组中的第K个元素 int FindKth(int a[], int b[], int k, int astart, int aend, int bstart, int bend) { ; ...

  2. java反射机制学习笔记

    内容引用自:https://www.cnblogs.com/wkrbky/p/6201098.html https://www.cnblogs.com/xumBlog/p/8882489.html,本 ...

  3. 三、Kubernetes_V1.10集群部署-master-部署flanne网络

    1. etcdctl --ca-file=/etc/etcd/ssl/ca.pem --cert-file=/etc/etcd/ssl/server.pem --key-file=/etc/etcd/ ...

  4. excel常用公式--逻辑运算类

    if:  IF(logical_test, value_if_true, [value_if_false]). and: 逻辑判断,相当于“并”. or: 逻辑判断,相当于“或”.

  5. Qt - 获取本机网络信息

    目的: 获取本机的主机名.IP地址.硬件地址等网络信息. 工具: 使用Qt提供的网络模块QtNetwork(pro文件里面加network): 使用Qt提供的类QHostInfo.QNetworkIn ...

  6. poj2352(树状数组)

    题目链接:https://vjudge.net/problem/POJ-2352 题意:在直角坐标系中给出n个点的 (x,y),(0<=x,y<=32000),定义每个点的level为(x ...

  7. 重装java后hadoop配置文件的修改

    1.删除hdfs-site.xml中dfs.namenode.name.dir目录和dfs.datanode.data.dir目录 然后 hdfs namenode -format 不然将无法启动na ...

  8. http请求跨域问题分析

    http请求跨域问题分析 个人认为可能涉及很多http的知识,本人才疏学浅不敢妄自揣测,只是做个笔记为了以后对比理解,从原生fetch说起吧,前提假设有个后端服务,我用express来模拟,如下: v ...

  9. spring配置添加多个事务(转)

    大多数项目只需要一个事务管理器.然而,有些项目为了提高效率.或者有多个完全不同又不相干的数据源,最好用多个事务管理器.机智的Spring的Transactional管理已经考虑到了这一点,首先分别定义 ...

  10. SpringBoot_01

    一.初识springboot 个人总结:springboot是一个开发更加便捷的spring的技术框架,通过引入启动器便可以快捷的让spring框架和其他框架进行整合, springboot很容易上手 ...