poj 1182 食物链(带权并查集)
2015-07-14 12:14
302 查看
题目链接:
点击打开链接
题目大意:
给出一些关系,判断矛盾的个数,先说出的未被反驳的语句我们认为是正确的
题目分析:
这种题很明显是集合的问题,但是是一个有关系的集合,所以我们可以利用带权的并查集来解决,主要做法如下:
我们定义两个数组,第一个数组就是实现并查集的fa数组,用来判断集合关系,把每个集合看做一条链,可以得到这条链的一端,我们定义它为根,因为关系满足传递性,所以我们可以通过关系的传递性推倒出当前条件下两者的关系,然后根据当前的可判断的关系来判断刚刚给出的关系是否出现矛盾
那么具体做法就是:
1.rank数组0表示当前点与根同类,1表示当前点能吃根,2表示当前点被根吃,如此定义下正好能够通过模运算,达到关系的传递性
2.首先用rank数组标记当前点与根的关系,然后我们可以利用传递性,得到任意两点间的关系((rank[a]-rank[b]) %3)
3.可以再路径压缩中维护这种关系,rank[a] = (rank[a]+rank[fa[a]] )%3, 通过将当前点到之前根的关系,加上之前根到当前根的关系,维护当前点到根的关系
4.每次添加新关系导致两个集合(两条链)连接,我们可以通过当前点的关系,反推出两个根的关系,也就是rank[ffa] = rank[a]-rank[b]+f
具体代码如下,这是带权并查集的经典题同样也是模板题,把并查集理解为一条链更容易理解
代码如下:
点击打开链接
题目大意:
给出一些关系,判断矛盾的个数,先说出的未被反驳的语句我们认为是正确的
题目分析:
这种题很明显是集合的问题,但是是一个有关系的集合,所以我们可以利用带权的并查集来解决,主要做法如下:
我们定义两个数组,第一个数组就是实现并查集的fa数组,用来判断集合关系,把每个集合看做一条链,可以得到这条链的一端,我们定义它为根,因为关系满足传递性,所以我们可以通过关系的传递性推倒出当前条件下两者的关系,然后根据当前的可判断的关系来判断刚刚给出的关系是否出现矛盾
那么具体做法就是:
1.rank数组0表示当前点与根同类,1表示当前点能吃根,2表示当前点被根吃,如此定义下正好能够通过模运算,达到关系的传递性
2.首先用rank数组标记当前点与根的关系,然后我们可以利用传递性,得到任意两点间的关系((rank[a]-rank[b]) %3)
3.可以再路径压缩中维护这种关系,rank[a] = (rank[a]+rank[fa[a]] )%3, 通过将当前点到之前根的关系,加上之前根到当前根的关系,维护当前点到根的关系
4.每次添加新关系导致两个集合(两条链)连接,我们可以通过当前点的关系,反推出两个根的关系,也就是rank[ffa] = rank[a]-rank[b]+f
具体代码如下,这是带权并查集的经典题同样也是模板题,把并查集理解为一条链更容易理解
代码如下:
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #define MAX 50007 using namespace std; int rank[MAX]; int fa[MAX]; int ans; int _find ( int x ) { //return x == fa[x]?x:fa[x]=find(x); if ( x == fa[x] ) return x; int temp = fa[x]; fa[x] = _find ( fa[x]); rank[x] = (rank[x] + rank[temp])%3; return fa[x]; } void init ( ) { for( int i = 0 ; i < MAX ; i++ ) fa[i] = i; } void _union ( int a , int b , int f ) { int ffa = _find ( a ); int fb = _find ( b ); if ( ffa == fb ) return; fa[ffa] = fb; rank[ffa] = (f+rank[b]-rank[a]+3)%3; } int n,k,u,v,f; bool check ( int u , int v , int f ) { if ( u > n || v > n ) return false; if ( f == 1 && u == v ) return false; if ( _find(u) == _find(v)) return ((rank[u] - rank[v])%3+3)%3 == f; else return true; } int main ( ) { scanf ( "%d%d" , &n , &k ); { ans = 0; memset ( rank , 0 , sizeof ( rank )); init (); for ( int i = 0 ; i < k ; i++ ) { scanf ( "%d%d%d" , &f , &u , &v ); f--; if ( check ( u , v ,f )) _union ( u , v , f ); else ans++; } printf ( "%d\n" , ans ); } }
相关文章推荐
- 简单的除法(简单枚举优化)
- Java4Android-面向对象基础1
- 一、动态规划(1)相似基因
- jquery.validate.js【简单实用的表单验证框架】
- 技术社交以及技术人员互助网站
- [LeetCode] Longest Substring with At Most Two Distinct Characters
- Java设计模式之单例模式
- 字典转模型的过程中,空值和id特殊字符的处理
- HDU4642:Fliping game
- ios开发 向右滑动手势实现返回.在NavigationController中如何设置
- THINKPHP 解决模块不存在时出现空页面的问题
- 生产者消费者练习
- C++程序中启动线程的方法
- Centos 7 安装jdk1.7
- RDIFramework.NET框架SOA解(集Windows服务、WinForm形式和IIS发布形式)-分布式应用程序
- 欢迎使用CSDN-markdown编辑器
- ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
- DataSet用法详细 转
- hdu5261
- jquery获得当前html页面源码的方法