POJ1182食物链

公认的并查集经典。题目不贴了,链接在这里http://poj.org/problem?id=1182

并查集的基础功能是 判断两个元素是否属于同一个集合 和 合并元素到同一个集合。

更高的层次的应用是 判断和维护两个元素的关系。

数组Fa[ x ]表示x所在集合的根节点,Rank[ x ]表示x和x所在集合根节点的关系。

这篇博客深入的解释了这道题目,图文并茂,强烈推荐 

https://blog.csdn.net/niushuai666/article/details/6981689

向量的思想实在是惊艳,一下子就把这个问题完美的刻画出来。

题目说“动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A”。

这构成一个循环,与取模运算有很大的相似性。所以我们做出如下假设:

Rank[ x ]=0表示x和Fa[ x ]同类
Rank[ x ]=1表示Fa[ x ]吃x
Rank[ x ]=2表示Fa[ x ]被x吃

这样假设之后,关系就能够通过加减进行计算。

例如:

如果A吃B, B吃C,那么按照向量的计算,A和C的关系就是AB加BC,即AC=AB+BC,按照上面假设等于2,结果就是A被C吃

如果A吃B,A吃C,BC=AC-AB=0,B和C是同类

.......

这也解释了为什么输入的D要减一

 

之前有个疑惑Find函数为什么能够维护正确的关系。仔细想,发现递归真是奇妙。

详细的看一下这段代码

int Find(int e)
{
    if(Fa[e]==e)return e;
    int oldF=Fa[e];//保存当前节点的父节点
    Fa[e]=Find(Fa[e]);//当前节点指向根节点
    Rank[e]=(Rank[oldF]+Rank[e])%3;
  //父节点的值已经在上层函数中被更新,Rank[oldF]表示的是oldF和根节点的关系
  //Rank[e]还是保持着e和oldF的关系
  //执行更新语句之后,Rank[e]表示e和根节点的关系
return Fa[e]; }

 

代码:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#define DEBUG(x) cout<<#x<<" = "<<x<<endl
using namespace std;
const int MAXN=5e4+10;
int N,K;
int Fa[MAXN];
int Rank[MAXN];
///Rank表示关系
///0表示x和Fa[x]同类
///1表示Fa[x]吃x
///2表示Fa[x]被x吃
int Find(int e)
{
    if(Fa[e]==e)return e;
    int oldF=Fa[e];
    Fa[e]=Find(Fa[e]);
    Rank[e]=(Rank[oldF]+Rank[e])%3;
    return Fa[e];
}
void Union(int a,int b,int r)
{
    int t1=Find(a);
    int t2=Find(b);
    if(t1!=t2){
        Fa[t2]=t1;
        Rank[t2]=(Rank[a]+r+3-Rank[b])%3;
    }
}
void Init()
{
    for(int i=0;i<=N ;i++ ){
        Fa[i]=i;
        Rank[i]=0;
    }
}
int main()
{
//    freopen("in.txt","r",stdin);
    int cnt=0;
    scanf("%d%d",&N,&K);
    Init();
    while(K--){
        int D,X,Y;
        scanf("%d%d%d",&D,&X,&Y);
        if(X>N||Y>N){cnt++;continue;}
        if(D==2&&X==Y){cnt++;continue;}
        int r1=Find(X);
        int r2=Find(Y);
        if(r1==r2){
            if((Rank[Y]-Rank[X]+3)%3!=D-1)cnt++;
        }
        else {
            Union(X,Y,D-1);
        }
    }
    printf("%d\n",cnt);
}

 

posted @ 2018-08-22 19:24  MalcolmMeng  阅读(118)  评论(0编辑  收藏  举报