动物王国的食物链

  这一题有两种思路,先介绍第一种:

  题目是中文的,我就不翻译了,也很好理解,就是一个A-B-C-A的一个循环的食物链,给定一些条件,问你哪些条件是错的

  这一题,是一道比较经典的查并集的题目,那么这一题的思想是什么呢,对于给定的条件,x和y属于什么集合其实并没有给出,而且x和y之间还有其他的捕食的关系

  但是我们现在假设,如果x和y都是属于同一类的,那么如果x属于A,那么y也一定属于A,那么也就是说,x和y属于同一个集合总是同时成立的的,再假设,如果x可以吃y,那么如果x属于A,那么y一定属于B,x属于B,那么y一定属于C或x属于C,那么y一定属于A,也就是说,在捕食关系中,y属于x的下一个集合一定成立的(A-B-C-A)

  那么我们就可以用查并集来很好的维护这个关系,我们给x和y赋予A,B,C三个属性,并且用查并集来维护这些属性,如果x和y都属于一个集合,那么我们就要分别合并x和y的三个属性,如果属于不是关系,那么我们就把y的与x的下一个关系的集合进行合并,这三个属性可以用k,k+N,k+2*N的形式表现,这样就可以非常快速的维护关系了(因为对于找根的操作而言,查并集是最快的)

  参考《挑战程序设计竞赛 第二版》

  PS:查并集我用的是按大小合并的方式,本来这种方式可以有效的降低搜索的时间,但是因为这一题比较特殊(集合比较多)所以递归时间并没有减少很多,另外大家合并的时候一定要检查是不是同一个集合,不然会出错,并且MLE

  另外这题,真是尼玛,有BUG,只能交单次数据(也就是不能while(~scanf())),真是个脑残bug

  

  

 #include <stdio.h>
#include <stdlib.h>
#include <string.h> typedef int Position; Position Find(Position);
void Union_Set(Position, Position);
int If_Same_Set(Position, Position); static int *Set = NULL; int main(void)
{
int N, case_sum, i;
int ans = , inform, x, y;
scanf("%d%d", &N, &case_sum);
Set = new int[ * (N + )];
for (i = ; i <= * N; i++) Set[i] = -;
for (i = ; i < case_sum; i++)
{
scanf("%d%d%d", &inform, &x, &y);
if (x > N || y > N)//如果在区域外,直接判断出错
{
ans++;
continue;
}
else if (inform == )
{
if (If_Same_Set(x, y + N) || If_Same_Set(x, y + * N))
//如果已经是捕食集合中,出错
ans++;
else//否则,则把xy的三个属性分别合并
{
Union_Set(x, y);
Union_Set(x + N, y + N);
Union_Set(x + * N, y + * N);
}
}
else if (inform == )
{
if (If_Same_Set(x, y) || If_Same_Set(x, y + * N))
//如果已经在非捕食集或已统一集合,出错
ans++;
else
{
Union_Set(x, y + N);
Union_Set(x + N, y + * N);
Union_Set(x + * N, y);
}
}
}
printf("%d\n", ans);
delete Set;
return ;
} Position Find(Position x)
{
//路径压缩
if (Set[x] < )
return x;
else
return Set[x] = Find(Set[x]);
} int If_Same_Set(Position x, Position y)
{
return Find(x) == Find(y);
} void Union_Set(Position x, Position y)
{
Position Rootx, Rooty;
Rootx = Find(x);
Rooty = Find(y); if (Rootx != Rooty)//按大小求并,千万要注意不能是同一个集合的合并,不然会MLE
{
if (Set[Rootx] < Set[Rooty])
{
Set[Rootx] += Set[Rooty];
Set[Rooty] = Rootx;
}
else
{
Set[Rooty] += Set[Rootx];
Set[Rootx] = Rooty;
}
}
}

  第二种思路,只用到一个查并集和一个偏移量集:思路来源http://poj.org/showmessage?message_id=105601

  我们先定义B与A之间的偏移关系:

  存在偏移量集delta,如果|delta[B]-delta[A]|%3,则定义

    =0  B与A是同类

    =1  B是A的食物

    =2  B是A的天敌

  我们规定,每一次关系的确定,最后B与A都会集中到一个集合(广义集合),其中的关系在偏移量集中找

  比如如果规定1吃2,2吃3,4吃2,则说明如果当所有元素的初始化绝对偏移量是0时,则2的绝对偏移量是1,3的绝对偏移量是2(delta[3]-delta[1]=2所以3是1的天敌,符合问题描述),同时4的绝对偏移量是0(绝对偏移量只取012),同样满足关系。但是现在的问题是,我们的集合最后都会搜索到根的,如果我们仅改变某个元素的一次偏移量,可能这个元素就会和根的关系就会发生变化,但是根与其包括的所有元素的关系都是先确定好了,所以我们只用把根的关系都进行偏移就可以,比如我们再定义5吃6,6吃7,8吃6,(偏移量:5-0,6-1,7-2,8-0)同时再定义1吃5,9吃8,如果我们假设5合并到1上,那么5对1的相对偏移量应该是1,而和5这个集合的元素的绝对偏移量应该全部都+1,才能保证相对偏移量不变,也就是可以看成,以5为起点,5这个集合的所有元素全部加上5的绝对偏移量1

  比如处理8吃9的时候,因为5的绝对偏移量为1,所以9的偏移量为delta[9]-delta[8]+5的绝对偏移量+1=0-0+1+1=2,刚好说明9是8的食物(此时8的绝对偏移量为0+1),同时也是5的食物,而且还是1的天敌,符合题意

  我们最后可以用(delta[x]-delta[y]+d)%3=delta[rootx]的方法来添加绝对偏移量,对于根的绝对偏移量发生变化时,我们可以不必立马对根以下的元素全部进行改变,也改变不了,我们只要查询的时候进行操作再重新记录就可以了

  

 #include <iostream>
#include <functional> using namespace std; typedef int Position; Position *pos = NULL;//查并集
Position *delta = NULL;//偏移量集 int Find(Position);
bool Check(Position, Position, const int); int main(void)
{
int N, case_sum, ans = , inform, x, y;
scanf("%d%d", &N, &case_sum);
pos = new Position[N + ];
delta = new Position[N + ];
for (int i = ; i <= N; i++)
pos[i] = i;
memset(delta, , sizeof(Position)*(N + )); for (int i = ; i < case_sum; i++)
{
scanf("%d%d%d", &inform, &x, &y);
if (x > N || y > N)
ans++;
else if (!Check(x, y, inform - ))
ans++;
}
printf("%d\n", ans);
delete pos; delete delta;
return ;
} int Find(Position x)
{
//路径压缩
if (pos[x] == x)
return x;
int tmp = Find(pos[x]); delta[x] = (delta[x] + delta[pos[x]]) % ;
pos[x] = tmp;
return tmp;
} bool Check(Position x, Position y, const int inform)
{
//设delta[x]为x到根的偏移量
Position Rootx, Rooty;
Rootx = Find(x);
Rooty = Find(y); if (Rootx == Rooty)
{
if ((delta[y] - delta[x] + ) % != inform)
return false;//如果在同一个集合,不满足偏移,说明出错了
else return true;//满足偏移量,则说明正确
}
//直接合并
pos[Rooty] = Rootx;
delta[Rooty] = (delta[x] - delta[y] + inform + ) % ;
return true;
}

  

DisJSet:食物链(POJ 1182)的更多相关文章

  1. 食物链 poj 1182

    C - 食物链 Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Submit Stat ...

  2. 洛谷 P2024 食物链 POJ 1182 Label:并查集Turbo

    题目描述 动物王国中有三类动物 A,B,C,这三类动物的食物链构成了有趣的环形.A 吃 B,B 吃 C,C 吃 A. 现有 N 个动物,以 1 - N 编号.每个动物都是 A,B,C 中的一种,但是我 ...

  3. 食物链 POJ 1182(种类并查集)

    Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到 ...

  4. Day5 - F - 食物链 POJ - 1182

    动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A.现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种.有人用两种说法 ...

  5. 食物链 POJ - 1182 (并查集的两种写法)

    这是一个非常经典的带权并查集,有两种写法. 1 边权并查集 规定一下,当x和y这条边的权值为0时,表示x和y是同类,当为1时,表示x吃y,当为2时,表示x被y吃. 一共有三种状态,如图,当A吃B,B吃 ...

  6. poj 1182:食物链(种类并查集,食物链问题)

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

  7. POJ 1182 食物链

    G - 食物链 Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Submit Stat ...

  8. POJ 1182 食物链(种类并查集)

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

  9. poj 1182 食物链 (带关系的并查集)

      食物链 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 44835 Accepted: 13069 Description 动 ...

随机推荐

  1. java导出txt文本

    页面 项目结构 html代码 <html> </head> <body> <form action="down/downLoad" met ...

  2. eclipse启动tomcat错误:A Java Exception has occurred

    在tomcat bin目录下执行startup.bat可以正常启动,但在eclipse下安装了tomcat插件并且配置tomcat路径后启动且报错:A Java Exception has occur ...

  3. 设置div居中

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. POJ1328Radar Installation(区间点覆盖问题)

    Radar Installation Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 68597   Accepted: 15 ...

  5. vi显示行号

    vi显示行号   :set nu         带行号查看,并不改变文件内容:set nonu     取消带行号查看在每个用户的主目录下,都有一个 vi 的配置文件".vimrc&quo ...

  6. nuget pack

    nuget spec nuget setApiKey yourkeynuget pack PluginMvc.Framework.csproj -Prop Configuration=Releasen ...

  7. C语言转换大小写

    #include <stdio.h> #include <ctype.h> // Contains the tolower prototype void main (void) ...

  8. iOS-Auto property synthesis will not synthesize property 'delegate'; it will be implemented by its super

    今天在XCode6.3上面重写TabBar的时候,自定义tabBar的代理遇到的一个问题 在重写tabBar的代理的时候遇到了一个警告. 解决方法: 在.m文件中 警告消失.

  9. BSGS算法_Baby steps giant steps算法(无扩展)详解

    Baby Steps-Varsity Giant Step-Astronauts(May'n・椎名慶治) 阅读时可以听听这两首歌,加深对这个算法的理解.(Baby steps少女时代翻唱过,这个原唱反 ...

  10. firefox查看微信公众平台的数据分析时就出现不信任链接怎么办?

    昨天用360清理垃圾后火狐主页的快速拨号栏消失了,整了半天还是无法使用就重装了一下firefox,导入备份的书签,添加自己所需的附加组件,设置为隐私模式,开始继续体验.按惯例打开微信公众平台,查看数据 ...