POJ 1182 食物链 【并查集】

时间:2022-08-16 09:23:57

解题思路:首先是没有思路的----然后看了几篇解题报告

http://blog.csdn.net/ditian1027/article/details/20804911

http://poj.org/showmessage?message_id=152847

http://blog.163.com/jiazheng2222%40126/blog/static/16963238320101258935104/

这是discuss里面的一篇分析---

 http://poj.org/showmessage?message_id=152847
我的理解是,对于集合里的任意两个元素a,b而言,它们之间必定存在着某种联系,
>
> 因为并查集中的元素均是有联系的,否则也不会被合并到当前集合中。那么我们
>
> 就把这2个元素之间的关系量转化为一个偏移量,以食物链的关系而言,不妨假设
>
> a->b 偏移量0时 a和b同类
>
> a->b 偏移量1时 a吃b
>
> a->b 偏移量2时 a被b吃,也就是b吃a
>
> 有了这些基础,我们就可以在并查集中完成任意两个元素之间的关系转换了。
>
> 不妨继续假设,a的当前集合根节点aa,b的当前集合根节点bb,a->b的偏移值为d-1(题中给出的询问已知条件)
>
> (1)如果aa和bb不相同,那么我们把bb合并到aa上,并且更新delta[bb]值(delta[i]表示i的当前集合根节点到i的偏移量)
>
> 此时 aa->bb = aa->a + a->b + b->bb,可能这一步就是所谓向量思维模式吧
>
> 上式进一步转化为:aa->bb = (delta[a]+d-1+3-delta[b])%3 = delta[bb],(模3是保证偏移量取值始终在[0,2]间)
>
> (2)如果aa和bb相同,那么我们就验证a->b之间的偏移量是否与题中给出的d-1一致
>
> 此时 a->b = a->aa + aa->b = a->aa + bb->b,
>
> 上式进一步转化为:a->b = (3-delta[a]+delta[b])%3,
>
> 若一致则为真,否则为假。
>
> 希望可以对LS有所帮助 :]

  

下面是自己的体会

pre[x]:表示x的父节点为pre[x]
p=find(x),其中p表示x的根节点
relation[x] :表示节点x与其根节点的关系,
relation[x]=p->x(因为后面要用到向量,所以先把向量的方向说明出来,relation[x]向量代表从根节点p指向x的向量)
relation[x]=0 表示p与x同类
relation[x]=1 表示p吃x
relation[x]=2 表示x吃p
-----------------------------------------------------------------------------------
对于给定的一句话 d,x,y
先判断x,y是否在同一个集合关系(集合是按照能够判断x,y关系来划分的)
if(x,y在同一个集合)
{
判断说的这句话的真假 ;
}
else
{
这句话认为为真,将x,y合并起来;
}
-----------------------------------------------------------------------------------
判断一句话的 真假可以有两种办法
(方法一)直接列出所有为真的情况,如果这句话不符合列举出的所有情况,则这句话为假
1)
d==1 表示x,y为同类
relation[x] relation[y]
0 0
1 1
2 2
所以如果relation[x]!=relation[y],则这句话为假话
2)
d==2 表示x吃y
relation[x] relation[y]
0 2 //此时x与根节点同类,要让x吃y,relation[y]=2
2 1 //此时x吃根节点,要让x吃y,则y与根节点同类,relation[y]=1
1 0 //此时x被根节点吃,要让x吃y,则y应该吃根节点,relation[y]=1
如果不满足这三组对应的 值,则 这句话为假 (方法二)
详细见 http://poj.org/showmessage?message_id=152847
按照向量来做
x->y=x->p+p->y//因为此时p=q,所以可以将p换成q
=-relation[x]+relation [y]
=relation[y]-relation[x]//再进一步处理,为了防止为表达式的值为负数,给它加上3,
=(relation[y]-relation[x]+3)%3 // 为使表达式的值在0到2之间,给表达式模 上3
又因为题目中给的是 d==1 x,y为同类,对应于我们规定的同类为0,应该将d-1
所以判断我们计算出的偏移量和说的那句话的偏移量是否一致,如果不一致,则说的 假话

((relation[y]-relation[x]+3)%3) !=d-1,则这句话为假话 ---------------------------------------------------------------------------------------
p,q不同时 合并 x,y
将q合并到p上,同时更新relation[q]
p->q=p->x+x->y+y->q
=relation[x]+(d-1) +(-relation[y])//同样为防止表达式的值为负,加上3
=(relation[x]-relation[y]+(d-1)+3) %3//为了使表达式的值在0到2之间,模上3
即 relation[q]=(relation[x]-relation[y]+(d-1)+3) %3 ----------------------------------------------------------------------------------------
压缩路径的时候,同时更新relation[]数组
详细见:http://blog.csdn.net/ditian1027/article/details/20804911
现在知道儿子节点x, 父亲节点 fx,爷爷节点ffx,要求ffx->x
则 ffx->x=ffx->fx+fx->x
=relation[fx]+relation[x] 即 relation[x]=(relation[x]+relation[tmp])%3
将fx记作x的亲生父亲,又因为find()函数是带路径压缩的,经过压缩后,x的父亲节点变为fx',不能用来计算
而我们需要的是fx的值 ,所以用tmp将它记录下来,再压缩
----------------------------------------------------------------------------------------

  反思:用向量表示relation[]数组时,向量起点和向量的终点一定要搞清楚,要不然后面的式子符号就会不对

下面是两种不同判断说话真假的代码

#include<stdio.h>
#define maxn 50010
int pre[maxn],relation[maxn];
int find(int a)
{
int tmp;
tmp=pre[a];
if(a!=pre[a])
pre[a]=find(pre[a]);
relation[a]=(relation[a]+relation[tmp])%3;
return pre[a];
} void unionroot(int x,int y,int d)
{
int p,q;
p=find(x);
q=find(y);
pre[q]=p;
relation[q]=(relation[x]-relation[y]+3+d-1)%3;
} int main()
{
int i,n,k,sum,x,y,p,q,d;
scanf("%d %d",&n,&k);
for(i=0;i<=maxn;i++)
{
pre[i]=i;
relation[i]=0;
}
sum=0;
while(k--)
{
scanf("%d %d %d",&d,&x,&y);
p=find(x);
q=find(y);
if((x>n||y>n)||(x==y&&d==2))
{
sum++;
continue;
}
if(p==q)
{
if((relation[y]-relation[x]+3)%3!=d-1)
sum++;
}
else
unionroot(x,y,d);
}
printf("%d\n",sum);
}

  

#include<stdio.h>
#define maxn 50010
int pre[maxn],relation[maxn];
int find(int a)
{
int tmp;
tmp=pre[a];
if(a!=pre[a])
pre[a]=find(pre[a]);
relation[a]=(relation[a]+relation[tmp])%3;
return pre[a];
} void unionroot(int x,int y,int d)
{
int p,q;
p=find(x);
q=find(y);
pre[p]=q;
relation[p]=(relation[y]-relation[x]+3+d-1)%3;
} int main()
{
int i,n,k,sum,x,y,p,q,d;
scanf("%d %d",&n,&k);
for(i=0;i<=maxn;i++)
{
pre[i]=i;
relation[i]=0;
}
sum=0;
while(k--)
{
scanf("%d %d %d",&d,&x,&y);
p=find(x);
q=find(y);
if((x>n||y>n)||(x==y&&d==2))
{
sum++;
continue;
}
if(p==q)
{
if(d==1&&relation[x]!=relation[y])
++sum;
if(d==2)
{
if(relation[x]==0&&relation[y]!=2)
++sum;
if(relation[x]==1&&relation[y]!=0)
++sum;
if(relation[x]==2&&relation[y]!=1)
++sum;
} }
else
unionroot(x,y,d);
}
printf("%d\n",sum);
}

  

POJ 1182 食物链 【并查集】的更多相关文章

  1. POJ 1182 食物链 &lbrack;并查集 带权并查集 开拓思路&rsqb;

    传送门 P - 食物链 Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Submit  ...

  2. poj 1182 食物链 并查集 题解《挑战程序设计竞赛》

    地址 http://poj.org/problem?id=1182 题解 可以考虑使用并查集解决 但是并不是简单的记录是否同一组的这般使用 每个动物都有三个并查集 自己 天敌 捕食 并查集 那么在获得 ...

  3. POJ 1182 食物链&lpar;并查集的使用)

    食物链 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 81915   Accepted: 24462 Description ...

  4. poj 1182 食物链 并查集的又一个用法

    食物链   Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 41584   Accepted: 12090 Descripti ...

  5. POJ 1182食物链&lpar;并查集)

    食物链Time Limit: 1000MS Memory Limit: 10000KTotal Submissions: 85474 Accepted: 25549Description动物王国中有三 ...

  6. POJ - 1182 食物链 并查集经典

    思路:设r(x)表示节点x与根结点的关系,px表示x的根结点.记录每个节点与其父节点的关系,就能很方便知道每个节点以及和它的父节点的关系. struct node{ int par; //父亲节点 i ...

  7. poj——1182食物链 并查集(提升版)

    因为是中文题,题意就不说了,直接说思路: 我们不知道给的说法中的动物属于A B C哪一类,所以我们可以用不同区间的数字表示这几类动物,这并不影响结果,我们可以用并查集把属于一类的动物放在一块,举个例子 ...

  8. POJ 1182 食物链 &lpar;并查集&rpar;

    食物链 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 50601   Accepted: 14786 Description ...

  9. POJ 1182 食物链&lpar;并查集)

    题目链接 经过宝哥的讲解,终于对这种问题有了进一步的理解.根据flag[x]和flag[y]求flag[tx]是最关键的了. 0吃1,1吃2,2吃0. 假设flag[tx] = X; 那么X + fl ...

  10. poj 1182 &lpar;关系并查集&rpar; 食物链

    题目传送门:http://poj.org/problem?id=1182 这是一道关系型并查集的题,对于每个动物来说,只有三种情况:同类,吃与被吃: 所以可以用0,1,2三个数字代表三种情况,在使用并 ...

随机推荐

  1. HTML光标样式

    HTML光标样式 把你的光标放到相应文字上鼠标显示效果   cursor:auto;   自动  cursor:zoom-in;   放大镜  cursor:zoom-out;   缩小镜  curs ...

  2. 网页引导:jQuery插件实现的页面功能介绍引导页效果

    现在很多网站不仅是介绍,更多的是有一些功能,怎么样让客户快速的知道网站有哪些功能呢?这里pagewalkthrough.js插件能帮我们实现,它是一个轻量级的jQuery插件,它可以帮助我们创建一个遮 ...

  3. Burp Suite使用介绍

    Burp Suite使用介绍(一)  22人收藏 收藏 2014/05/01 19:54 | 小乐天 | 工具收集 | 占个座先 Getting Started Burp Suite 是用于攻击web ...

  4. SQL &colon; 在SQL Server 2008&lpar;Or Express&rpar;中如何Open并编辑数据表【转】

    来源:http://www.cnblogs.com/wsdj-ITtech/archive/2011/04/28/2031601.html 通常在SQL Server 2005中,我们可以通过SQL ...

  5. &lbrack;MFC美化&rsqb; MFC界面UI库总结

    稍微说下自己用过的感受: 1.SkinMagic 动态库DLL使用,(有VC6版本的静态链接库,没能成功调用).对控件:菜单和下拉框(下拉滚动条)有问题.不能*设置颜色背景 皮肤格式:.smf,可使 ...

  6. webpy

    url处理 对于一个站点来说,URL 的组织是最重要的一个部分,因为这是用户看得到的部分,而且直接影响到站点是如何工作的,在著名的站点如:del.icio.us ,其URLs 甚至是网页界面的一部分. ...

  7. TOJ 数据结构实验--静态顺序栈

    描述 创建一个顺序栈(静态),栈大小为5.能够完成栈的初始化.入栈.出栈.获取栈顶元素.销毁栈等操作. 顺序栈类型定义如下: typedef struct {  int data[Max];    i ...

  8. Eclipse中Lombok的安装和注解说明

    Lombok 可用来帮助开发人员消除 Java 的重复代码,尤其是对于简单的 Java 对象(POJO),比如说getter/setter/toString等方法的编写.它通过注解实现这一目的. 官网 ...

  9. 【IL】IL指令详解

    名称 说明 Add 将两个值相加并将结果推送到计算堆栈上. Add.Ovf 将两个整数相加,执行溢出检查,并且将结果推送到计算堆栈上. Add.Ovf.Un 将两个无符号整数值相加,执行溢出检查,并且 ...

  10. CentOS 7 Apache 多端口部署 Web Apps 指南

    转载自简书,原作者xuyan0,链接https://www.jianshu.com/p/b34c78bf9bf0,如有侵权,请联系删除 导语 Apache web 服务器运行着互联网上超过半数的活跃的 ...