• POJ 1182 食物链 并查集


    这个题算是考察一下大家的逻辑思维,很可惜,我的还不行,这题我搜了别人的解题报告,没看几行字就不想看了,但今天又很想A了这题,又一次去搜了解题报告,看到了CSDN的博客上有一篇名为史上POJ 1182 最详细的解题报告,写得不错,我终于耐心看了下去,看完后,发现这个题和那个称重的并查集的题的思路基本上是一样一样的啊。

    下面详细讲一下:

    先定义每个动物的两种属性,一个是父结点是谁,一个是和父结点的关系,定义如下:

    struct Animal

    {

     int parent; //父结点的编号

    int relation;//和父结点的关系,0-和父结点是同类    1-被父结点吃    2-吃父结点

    } a[MAXN];

    下面推两个式子:(爷爷是父亲的父结点,父亲是儿子的父结点,现在要路径压缩,令儿子直接指向爷爷,儿子和爷爷的relation值如何确定?看下表:)

    p1  p2  p3(p1代表父亲的relation值,p2表示儿子的relation初值,p3代表儿子直接指向爷爷时,对爷爷的relation值)

    0   0  0

    0   1  1

    0  2  2

    1  0  1

    1  1  2

    1  2  0

    2  0  2

    2  1  0

    2  2  1

    很明显,像找规律一样,发现有如下关系:p3 = (p1+p2)%3  (公式1)

    有了这个公式,就好办了,再推一个公式:

    如果x是y的父结点,y的relation值为p1.

    如果改成y是x的父结点,那么x的relation值为p2,p1 和p2又有什么关系呢,显然有p1 = (3-p2)%3;(公式2)

    下面列举出所有情况,

    x吃y,p1 = 1,p2 = 2

    y吃x,p1=2,p2 = 1

    x与y是同类,p1=0,p2=0,满足上面的式子。

    当输入d,x,y时,x,y不在同一集合中,那么就合并x,y(是真话)

    在同一集合,根据和两子结点和父结点的relation值推出两子结点的relation值,和它说的不一样,它说的就是假话。

    我们不用启发式合并(把结点数少的合并到结点数多的上)

    而是直接把y所在的集合合并到x上,先令r1 = find(x), r2 = find(y).

     关键是要找到当r2以r1为根结点时r2的relation值。

    利用上面的公式1和公式2就能很快推出来,自己试着推一下吧````

    下面贴代码,没看明白的就看一下代码,兴许就明白了

    哦,再解释一句,这里之所以要把y所在集合合并到x的跟结点上,是为了巧妙的利用d的值,将x和y是同类以及x吃y一次性给解决了。

    拿只笔自己试试看

    View Code
     1 #include <cstdio>
     2 #define MAXN 50005
     3 struct node
     4 {
     5     int parent;
     6     int relation; //表示和父结点的关系,0-同类,1-被吃,2-吃
     7 } a[MAXN];
     8 int find(int x)
     9 {
    10     int s = x;
    11     int cur =0;
    12     int st[MAXN];
    13     while(a[s].parent > 0)
    14     {
    15         st[cur++] = a[s].relation;
    16         s = a[s].parent;
    17     }
    18     for(int i=cur-1; i>0; --i)
    19         st[i-1] = (st[i]+st[i-1])%3;
    20     cur = 0;
    21     while(s != x)
    22     {
    23         node tmp = a[x];
    24         a[x].parent = s;
    25         a[x].relation = st[cur++];
    26         x = tmp.parent;
    27     }
    28     return s;
    29 }
    30 void Union(int x,int y,int d)
    31 {
    32     int r1= find(x);
    33     int r2 = find(y);
    34     a[r2].parent = r1;
    35     a[r2].relation = (d+2+a[x].relation-a[y].relation)%3;
    36 }
    37 int main()
    38 {
    39 //    freopen("in.cpp","r",stdin);
    40     int n,k;
    41     scanf("%d%d",&n,&k);
    42     for(int i=1; i<=n; ++i)//初始化
    43     {
    44         a[i].parent = -1;
    45         a[i].relation = 0;
    46     }
    47     int num=0;
    48     while(k--)
    49     {
    50         int d,x,y;
    51         scanf("%d%d%d",&d,&x,&y);
    52         if(x > n || y>n || (d == 2 && x==y))
    53         {
    54             num++;
    55             continue;
    56         }
    57         int xp = find(x);
    58         int yp = find(y);
    59         if(xp != yp)
    60             Union(x,y,d);
    61         else
    62         {
    63             if(d == 1 && (a[x].relation+3-a[y].relation)%3 != 0)num++;
    64             if(d == 2 && (a[x].relation+3-a[y].relation)%3 != 2) num++;
    65         }
    66     }
    67     printf("%d\n",num);
    68     return 0;
    69 }

               

  • 相关阅读:
    网游开发中的可怕群体:单机派
    关卡设计的基本理论
    游戏程序员所需的知识体系
    关于SQL Server将一列的多行内容拼接成一行的问题讨论——之一(转)
    c# lmada 修改List内容
    c# 取sqlite库分组的第一行不对
    关于SQL Server将一列的多行内容拼接成一行的问题讨论(转)
    “打包的”爱情
    “婚礼哥”隔空喊爱:我要做你一生的北京情人
    北漂,都不敢奢望爱情?
  • 原文地址:https://www.cnblogs.com/allh123/p/3015276.html
Copyright © 2020-2023  润新知