poj1182食物链(种类并查集)

来源:互联网 发布:淘宝销量少的可以买吗 编辑:程序博客网 时间:2024/05/01 19:05

题目链接:poj1182

/*http://poj.org/problem?id=1182*//*题意:思路:首先,集合里的每个点我们都记录它与它这个集合(或者称为子树)的根结点的相对关系rank[]。0表示它与根结点为同类,1表示它吃根结点,2表示它被根结点吃。那么判断两个点x, y的关系,我们令fx = Find(x), fy = Find(y),即fx, fy分别为x,y子树的根结点。    1. 如果fx != fy,说明x, y暂时没有关系,那么关于他们的判断都是正确的,然后合并这两个子树。这里是关键,如何合并两个子树使得合并后的新树能保证正确呢?这里我们规定只能fy合并到fx. 那么合并后,rank[y]肯定要改变,那么改成多少呢?这里的方法就是找规律,列出部分可能的情况,就差不多能推出式子了。这里式子为 : rank[fy] = (rank[x]-rank[y]+3+d-1)%3;这里的d为判断语句中x, y的关系。还有个问题,我们是否需要遍历整个x子树并更新每个结点的状态呢?答案是不需要的,因为我们可以在find()函数稍微修改,即结点x继承它的父亲(注意是前父亲,因为路径压缩后父亲就会改变),即它会继承到fx结点的改变,所以我们不需要每个都遍历过去更新。    2. 如果fx = fy,说明x, y之前已经有关系了。那么我们就判断语句是否是对的,同样找规律推出式子。即if ( (rank[x]+1)%3 != rank[y] ), 那么这句话就是错误的。    3. 再对find()函数进行些修改,即在路径压缩前纪录前父亲是谁,然后路径压缩后,更新该点的状态(通过继承前父亲的状态,这时候前父亲的状态是已经更新的)。*/#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int inf = 0x3f3f3f3f;const int N = 50010;int f[N];int rank[N];//表示和父结点的关系(回溯路径压缩后,父结点即为根结点),0表示同类,1表示被吃,2表示吃void init(int &n){    for(int i = 1; i <= n; i ++)        f[i] = i,rank[i] = 0;}int find(int x){    if(x != f[x]){        int fx = f[x];        f[x] = find(f[x]);        //回溯由子节点与父节点的关系和父节点与根节点的关系找子节点与根节点的关系        rank[x] = (rank[x] + rank[fx])%3;    }    return f[x];}void Union(int x, int y, int d){    int fx = find(x);    int fy = find(y);    f[fy] = fx;//合并树,被x吃,所以以x的根为父    rank[fy] = (rank[x]-rank[y]+3+d-1)%3;}int main(){    int n,m,x,y,d;    scanf("%d%d",&n,&m);    int ans = 0;    init(n);    while(m --){        scanf("%d%d%d",&d,&x,&y);        if( x > n || y > n ||(d == 2 && x == y) ) ans ++;        else if(find(x) == find(y)){//表示两个点有关系,即在同一颗树上            if(d == 1 && rank[x] != rank[y]) ans ++;//不是同类            if(d == 2 && (rank[x]+1)%3 != rank[y]) ans ++;            //x吃y:a. rank[x] = 0, rank[y] = 1;            //      b. rank[x] = 1, rank[y] = 2;            //      c. rank[x] = 2, rank[y] = 0;        }        else Union(x, y, d);    }    printf("%d\n",ans);    return 0;}


这类题基本上就是套这个模板,其它种类并查集:poj2492    poj1703  poj1988
0 0
原创粉丝点击