poj1182 并查集 食物链
来源:互联网 发布:dnf账号数据出现异常 编辑:程序博客网 时间:2024/05/01 15:23
关键词:并查集 相对关系
思路:(用一个并查集就够了,同时对每个节点保持其到根结点相对类别偏移量)
1.p[x]表示x根结点。r[x]表示p[x]与x关系。r[x] == 0 表示p[x]与x同类;1表示p[x]吃x;2表示x吃p[x]。
2.怎样划分一个集合呢?
注意,这里不是根据x与p[x]是否是同类来划分。而是根据“x与p[x]能否确定两者之间关系”来划分,若能确定x与p[x]关系,则它们同属一个集合。
3.怎样判断一句话是不是假话?
假设已读入 D , X , Y , 先利用find_set()函数得到X , Y 所在集合代表元素 rx , ry ,若它们在同一集合(即 rx == ry )则可以判断这句话真伪( 据 2. ).
若 D == 1 而 r[X] != r[Y] 则此话为假。(D == 1 表示X与Y为同类,而从r[X] != r[Y]可以推出 X 与 Y 不同类。矛盾。)
若 D == 2 而 r[X] == r[Y] (X 与Y为同类)或者 r[X] == ( r[Y] + 1 ) % 3 (Y吃X )则此话为假。
4.上个问题中 r[X] == ( r[Y] + 1 ) % 3这个式子怎样推来?
假设有Y吃X,那么r[X]和r[Y]值是怎样?
我们来列举一下: r[X] = 0 && r[Y] = 2
r[X] = 1 && r[Y] = 0
r[X] = 2 && r[Y] = 1
稍微观察一下就知道r[X] = ( r[Y] + 1 ) % 3;
事实上,对于上个问题有更一般判断方法:
若 ( r[Y] - r[X] + 3 ) % 3 != D - 1 ,则此话为假。(来自poj 1182中Discuss )
5.其他注意事项:
在union_set( rx , ry )过程中若将S(ry)合并到S(rx)上,则相应r[ry]必须更新为ry相对于rx关系。怎样得到更新关系式?
//以下来自poj 1182 中Discuss
用向量运算。
现在已知关系: rx与x, ry与y, x与y,现在求rx与ry关系。学过向量应该能做出来吧。。。
在find_set( x )过程中要更新所有从x到rx路径上结点与代表元素相对关系。原因将在6中说明。
6.code + comment:
//===================================================================================
#include <iostream>
using namespace std;
void make_set( int [] , int [] , int );
int find_set( int [] , int [] , int );
void union_set( int [] , int [] , int , int , int , int , int );
int main()
{
int p[50001];
int r[50001];
int n, k;
int d, x, y, rx, ry;
int fs;
scanf( "%d%d" , &n , &k );
make_set( p , r , n );
fs = 0;
while ( k-- > 0 )
{
scanf( "%d%d%d" , &d , &x , &y );
if ( x > n || y > n || ( d == 2 && x == y ) )
{
fs++;
continue;
}
rx = find_set( p , r , x );
ry = find_set( p , r , y );
if ( rx == ry ) //可以确定X与Y关系,也就可以判断此话真伪。
if ( d == 1 && r[x] != r[y] )
fs++;
else
{
if ( d== 2 && r[x] != ( r[y] + 2 ) % 3 )
fs++;
}
else
union_set( p , r , rx , ry , x , y , d );
}
cout << fs << endl;
return 0;
}
void make_set( int p[] , int r[] , int n )
{
for ( int i = 0 ; i <= n ; i++ )
{
p[i] = i;
r[i] = 0;
}
}
int find_set( int p[] , int r[] , int x )
{
if ( p[x] == x ) return x;
int temp_px = p[x];
p[x] = find_set( p , r , p[x] ); //递归寻找元素x所在集合代表元素 rx
r[x] = ( r[temp_px] + r[x] ) % 3; //important. 更新r[]数组中x与代表元素相对关系。更新原因:代表元素在
//union_set操作中被改变了。至于这个式子推得.可以枚举rx与p[x], p[x]
//与x关系,然后观察得到。更好方法是向量运算。来自poj 1182 Discuss
return p[x];
}
void union_set( int p[] , int r[] , int rx , int ry , int x , int y , int d )
{
p[ry] = rx;
r[ry] = ( r[x] - r[y] + 2 + d ) % 3; //同上。这两个关系推得实际上是这道题关键所在。
}
//===================================================================================
- 食物链 POJ1182 -- 并查集
- poj1182 食物链 (并查集)
- poj1182 并查集 食物链
- poj1182食物链 并查集
- 并查集-POJ1182食物链
- POJ1182 - 食物链 - 并查集
- 并查集 食物链 POJ1182
- poj1182 食物链(并查集)
- POJ1182 食物链 并查集
- Poj1182食物链 (并查集)
- POJ1182 食物链(并查集)
- 【并查集】:poj1182,食物链
- POJ1182 食物链(并查集)
- POJ1182 食物链 并查集
- poj1182 食物链[并查集]
- poj1182 食物链(并查集)
- POJ1182 食物链【并查集】
- poj1182食物链(种类并查集)
- AES加密之openssl使用(2)
- hdu1059Dividing 多重背包二进制优化
- 【python】【scrapy】使用方法概要(一)
- javascript中的对象
- iphone视图间跳转之一:自定义视图控制器
- poj1182 并查集 食物链
- 【python】【scrapy】使用方法概要(三)
- ffmpeg使用指南相关网址
- 下拉菜单--字体练习
- 【python】【scrapy】使用方法概要(二)
- 703n无法进入路由管理界面reset无效重刷方法
- 【python】【scrapy】使用方法概要(四)
- 文本分类算法之决策树.ID3实现
- 下拉菜单--二级联动菜单练习