zoukankan      html  css  js  c++  java
  • POJ 1182食物链(分集合以及加权两种解法) 种类并查集的经典

    题目链接:http://icpc.njust.edu.cn/Problem/Pku/1182/

    题意:给出动物之间的关系,有几种询问方式,问是真话还是假话。

    定义三种偏移关系:

    x->y 偏移量0xy同类

    x->y 偏移量1xy

    x->y 偏移量2xy

    定义 rela[x]=rx->x;

    x,y不在同一个集合中,

    rx->ry=rx->x + x->y + y->ry=(rx->x)+(x->y)-(ry->y)可得

    rx->ry=rela[ry]=rela[x]+rela[y]+(x->y);

    由于关系仅限0,1,2,三种,对上面关系加三后取模才是正确的关系;

    如果x,y在同一个集合中,

    x->y=x->rx+rx->x;

    所以x->y=(3-rela[x]+rela[y])%3;

    种类并查集的问题我们必须清楚初始状况是什么样的还有状态的转移方程是什么。

    代码如下:

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 #define maxn 50005
     5 int n,k;
     6 int fa[maxn],rela[maxn];//分别表示父亲、子节点和父节点的关系 
     7 int ans;
     8 void init()
     9 {
    10     for(int i=1;i<=n;i++)
    11     {
    12         fa[i]=i;      /*relation:0、同类 1、吃2、被吃*/ 
    13         rela[i]=0;//初始状态下它和本身在一个集合中,关系为同类 
    14     }
    15     ans=0;
    16 }
    17 int find(int x)
    18 {
    19     if(x==fa[x])return fa[x];
    20     else
    21     {
    22         int tmp=fa[x];
    23         fa[x]=find(fa[x]);
    24     
    25         rela[x]=(rela[tmp]+rela[x])%3;//更新x与x的新的根结点的关系,ppx->x=ppx->px+px->x=rela[ppx]+real[px]; 
    26         return fa[x]; 
    27     }                                   //向量模式,rela为rootx->x的向量方向;为保证结果在[0,2]区间内,对3取模; 
    28 }
    29 int main()
    30 {
    31     cin>>n>>k;
    32     init();
    33     int f,a,b; 
    34     for(int i=1;i<=k;i++)
    35     {
    36         scanf("%d%d%d",&f,&a,&b);
    37         if(a>n||b>n)
    38         {
    39             ans++;
    40             continue;
    41         }
    42         if(f==2&&a==b)//x吃x ,不合法, 
    43         {
    44             ans++;
    45             continue;
    46         }
    47         int px=find(a);
    48         int py=find(b);
    49         if(px!=py)       //如果关系还未建立则建立关系       //合并的操作和查询是否正确的操作在主函数体中一起完成 
    50         {
    51             fa[py]=px;
    52             rela[py]=(3+rela[a]+(f-1)-rela[b])%3;
    53         }
    54         else
    55         {
    56             if(f==1&&rela[a]!=rela[b])//说是同类然而 计算得并不是,则说了假话 
    57             {
    58                 ans++;
    59                 continue;
    60             }
    61             if(f==2&&(3+rela[b]-rela[a])%3!=f-1)//两者之间三种状态题目中只有两种描述方式 
    62             {
    63                 ans++;
    64                 continue;
    65             }
    66         }
    67         
    68      } cout<<ans;
    69  } 

     下面是分集合操作的代码,集合划分成三个 i是同类集合,n+i是食物集合,2*n+i表示天敌集合,三个集合是绝对不相交的。

    代码如下:(因为只有吃,被吃,吃三种状态,所以检测的时候可能错误的状态就是两种)

     1 #include<cstdio>  
     2 #include<iostream>
     3 using namespace std;
     4 int fa[150100];  
     5 int x1,x2,x3,y1,y2,y3;
     6 int n,k,d,x,y,ans=0;
     7 int find(int x)
     8 {
     9     return fa[x]==x?x:fa[x]=find(fa[x]);
    10 }
    11 int main()
    12 {
    13     scanf("%d%d",&n,&k);
    14     for(int i=1;i<=n*3;i++) fa[i]=i;
    15     for(int i=1;i<=k;i++)
    16     {
    17         scanf("%d%d%d",&d,&x,&y);
    18         if(x>n||y>n)
    19         {
    20             ans++;
    21             continue;
    22         }
    23         x1=find(x);        //x表示自己
    24         x2=find(x+n);    //x+n表示x的食物
    25         x3=find(x+n*2); //x+2*n表示x的天敌
    26         y1=find(y);        //y表示自己
    27         y2=find(y+n);    //y+n表示y的食物
    28         y3=find(y+n*2);    //y+2*n表Y的是天敌
    29         if(d==1)
    30         {
    31             if(x1==y2||y1==x2) ans++;
    32             //给出的话表明x和y是同类,但是检测发现x吃y或者y吃x,产生矛盾。
    33             //在这次检测之中和x,y的天敌集合是没有关系的,因为天敌只是对一方的天敌
    34             //比如说x的天敌可能是y的同类,也可能是食物,也可能是天敌,所以说,是没有定论的美不需要检测 
    35             else
    36             {
    37                 fa[x1]=y1;//由于x和y是同类,所以他们的同类,天敌,食物都是一样的,所以需要全部合并 
    38                 fa[x2]=y2; 
    39                 fa[x3]=y3;
    40             }
    41         }
    42         else
    43         {
    44             if(x1==y1||x1==y2) ans++;//给出的话中表明x吃y,但是检测发现x和y是同类或者y吃x,发生矛盾 
    45             else
    46             {//集合的合并 
    47                 fa[y1]=x2;//y的同类都是x的食物 
    48                 fa[y2]=x3;//x吃y,y吃z,z吃x 
    49                 fa[y3]=x1;//将x集合归入y的天敌集合 
    50             }
    51         }
    52     }
    53     printf("%d",ans);
    54     return 0;
    55 }

     

  • 相关阅读:
    Intellij IDEA 常用快捷键
    @Transient注解----Hiberbate
    tomcat:域名指向项目名
    java实现全排列
    Bean不同配置方式的比较
    Spring MVC:在jsp中引入css
    Spring中Bean的作用域
    第9章 初识HAL固件库
    第8章 自己写库—构建库函数雏形
    第7章 使用寄存器点亮LED灯
  • 原文地址:https://www.cnblogs.com/randy-lo/p/12563371.html
Copyright © 2011-2022 走看看