zoukankan      html  css  js  c++  java
  • poj1182食物链(并查集+向量偏移)

    题目链接:http://poj.org/problem?id=1182

    搞了好久才弄明白。。。之前学并查集从来没想过能这么用,并查集+向量偏移!!!

    与一般并查集只开一个father数组不同,还要开一个ralation数组用来记录子节点与父节点的关系,对于此题,显然每个点对应根节点可能有三种关系,我用ralation[i]=0记为i与根节点是同类,relation[i]=1记为i被根节点吃,relation[i]=2记为i吃根节点。

    难点在于合并两个结点时如何更新节点对应的关系值(即relation[i],比如两个节点有不同的父节点,分别对应自己的父节点有一个关系值,而此时这两个点也有关系,需要合并,那么某棵树上的关系值很可能全都要改)。

    下面就是合并过程,结合图分析,向量思维。如图:

                      

                                图一                                         图二

    图一:表示m和n分别为两棵树的根节点,对应的关系为0,即与自己是同类。A对m的关系为1,即被m吃,同理b吃n;记向量m->a=1;n->b=2;

    图二:加入a和b的关系,a被b吃,即图中的向量a->b=2;此时要合并两棵树,即要求n对m的关系(我们定为n树合到m树),即向量m->n的值。

    根据向量的运算法则,m->n = m->a + a->b + b->n = m->a + a->b – n->b

    即relation[n]=(relation[a]+(d-1)-relation[b]+3)%3;  括号中加3是为了防止出现负号,对3取模是因为只有0,1,2三种关系。

    然后求更新relation[b](即m->b的值)就简单了,还是向量的思想,m->b = m->n +n->b,同上relation[b]=(relation[n]+relation[b])%3;  注意代码中我放到了getfather里面进行这一步。

    全部更新完之后图就变成了这样

     

    再配合代码看应该就很好理解了。。

     1 #include<cstdio>
     2 #include<cstring>
     3 const int maxn=50010;
     4 int f[maxn],r[maxn];  //f[]为父亲数组,r[]为关系数组
     5 int n,m,u,v;
     6 int d,ans;
     7 void init()  //初始化
     8 {
     9     for(int i=1;i<=n;i++)
    10     {
    11         f[i]=i;
    12         r[i]=0;
    13     }
    14 }
    15 
    16 int gf(int x)   //getfather
    17 {
    18    if(x!=f[x])
    19     {
    20         int t=f[x];
    21         f[x]=gf(t);
    22         r[x]=(r[x]+r[t])%3;   //向量偏移
    23     }
    24     return f[x];
    25 }
    26 
    27 void uni(int a,int b)  //合并
    28 {
    29     int pa=gf(a);
    30     int pb=gf(b);
    31     if(pa==pb)
    32     {
    33         if(d==1&&r[a]!=r[b]) ans++;
    34         else if(d==2&&(r[a]+1)%3!=r[b]) ans++;   //这点稍微想想就可得到
    35     }
    36     else {
    37         f[pb]=pa;
    38         r[pb]=(r[a]+d-1+3-r[b])%3;         //向量偏移!!!!!
    39     }
    40 }
    41 
    42 int main()
    43 {
    44         scanf("%d%d",&n,&m);    //注意此题单组输入,,不是以EOF结束输入。。否则WA!!!!!
    45         init();
    46         ans=0;
    47         for(int i=0;i<m;i++)
    48         {
    49             scanf("%d%d%d",&d,&u,&v);
    50             if(u>n||v>n) ans++;
    51             else if(d==2&&u==v) ans++;
    52             else
    53             uni(u,v);
    54         }
    55         printf("%d
    ",ans);
    56 
    57 }

     再看这两道题加以练习巩固。

    http://www.cnblogs.com/yijiull/p/6616138.html

    http://www.cnblogs.com/yijiull/p/6616130.html

  • 相关阅读:
    成为Java GC专家系列(3) — 如何优化Java垃圾回收机制
    成为JavaGC专家Part II — 如何监控Java垃圾回收机制
    JAVA缓存的实现
    Lock Less Java Object Pool
    跟屌丝大哥学习设计模式--享元模式
    数据库 -- 由数据库连接池引出的三种设计模式
    优秀博客推荐:各种数据结构与算法知识入门经典
    学习总结
    洛谷P3360偷天换日(树形DP)
    疯子的算法总结14--ST算法(区间最值)
  • 原文地址:https://www.cnblogs.com/yijiull/p/6527465.html
Copyright © 2011-2022 走看看