博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
NOI2001|POJ1182食物链[种类并查集 向量]
阅读量:5770 次
发布时间:2019-06-18

本文共 3339 字,大约阅读时间需要 11 分钟。

食物链
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 65430   Accepted: 19283

Description

动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。 
现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。 
有人用两种说法对这N个动物所构成的食物链关系进行描述: 
第一种说法是"1 X Y",表示X和Y是同类。 
第二种说法是"2 X Y",表示X吃Y。 
此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。 
1) 当前的话与前面的某些真的话冲突,就是假话; 
2) 当前的话中X或Y比N大,就是假话; 
3) 当前的话表示X吃X,就是假话。 
你的任务是根据给定的N(1 <= N <= 50,000)和K句话(0 <= K <= 100,000),输出假话的总数。 

Input

第一行是两个整数N和K,以一个空格分隔。 
以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。 
若D=1,则表示X和Y是同类。 
若D=2,则表示X吃Y。

Output

只有一个整数,表示假话的数目。

Sample Input

100 71 101 1 2 1 22 2 3 2 3 3 1 1 3 2 3 1 1 5 5

Sample Output

3

多了一种关系的种类并查集 v[i] 0和根同类 1吃根 2被根吃 可以发现1->0->2->1..... 可以从向量的角度思考,比如x->y +3%3是1的话说明x吃y v[x]就是x->fa[x]这个向量的值 发现D-1正好描述了X->Y这个向量的关系 路径压缩和合并的时候都画图用向量推一下就可以了

还有一种做法,是对每个动物x建立3个集合:x表示与x同类的动物,x+n表示要x吃的动物,x+2*n表示吃x的动物。

一些理解 并查集就是维护了一些关系 种类并查集是把知道关系的东西合并,通过分配一个值来处理 另一种做法是把同一类合并
////  main.cpp//  poj1182////  Created by Candy on 31/10/2016.//  Copyright ? 2016 Candy. All rights reserved.//#include
#include
#include
#include
using namespace std;const int N=5e4+5;inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){
if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f;}int n,m,c,x,y,ans=0;int fa[N],v[N];inline int find(int x){ if(x==fa[x]) return x; int root=find(fa[x]); v[x]=(v[x]+v[fa[x]])%3;//x->fa[x] + fa[x]->root return fa[x]=root;}inline int unn(int x,int y,int op){ int f1=find(x),f2=find(y); if(f1==f2){ if((-v[y]+v[x]+3)%3!=op) return 1; }else{ fa[f1]=f2; v[f1]=(op+v[y]-v[x]+3)%3; } return 0;}int main(int argc, const char * argv[]) { n=read();m=read(); for(int i=1;i<=n;i++) fa[i]=i,v[i]=0; for(int i=1;i<=m;i++){ c=read();x=read();y=read(); if(x>n||y>n||(c==2&&x==y)){ans++;continue;} ans+=unn(x,y,c-1); } printf("%d",ans); return 0;}

 

 

 

来自luogu题解,另一种做法这题显然要用并查集。因为只有3种动物,我的方法是对每个动物x建立3个集合:x表示与x同类的动物,x+n表示要x吃的动物,x+2*n表示吃x的动物。对于每个读入的描述D X Y,做以下处理:如果X或Y不再区间[1,n]中,这句是假话。D为1如果x+n或x+2*n与y在同一个集合中说明已知x和y不是同一种动物,这句是假话;否则,分别将x与y,x+n与y+n,x+2*n与y+2*n合并。D为2如果x与y在同一个集合中,说明已知x和y是同一种动物,这句是假话;如果x+2*n与y在同一个集合中,说明已知y吃x,这句是假话;否则,分别将x与y+2*n,x+n与y,x+2*n与y+n合并。

说起来很复杂,实现起来其实很简单,代码见下:#include
#include
using namespace std;int p[150001];int Find(int x) { return x == p[x] ? x : p[x] = Find(p[x]); }void Init(int n) { for (int i = 1; i <= 3 * n; i++) p[i] = i; }void Union(int x, int y){ int xx = Find(x), yy = Find(y); if (xx != yy) p[xx] = yy;}int main(){ int n, k, ans = 0; cin >> n >> k; Init(n); for (int i = 1; i <= k; i++) { int a, x, y; cin >> a >> x >> y; if (x > n || y > n || x < 1 || y < 1) { ans++; continue; } if (a == 1) { if (Find(x + n) == Find(y) || Find(x + 2 * n) == Find(y)) { ans++; continue; } Union(x, y); Union(x + n, y + n); Union(x + 2 * n, y + 2 * n); } else { if (Find(x) == Find(y) || Find(x + 2 * n) == Find(y)) { ans++; continue; } Union(x, y + 2 * n); Union(x + n, y); Union(x + 2 * n, y + n); } } cout << ans;}

 

转载地址:http://ediux.baihongyu.com/

你可能感兴趣的文章
【294天】我爱刷题系列053(2017.11.26)
查看>>
Microsoft发布了Azure Bot Service和LUIS的GA版
查看>>
Google发布Puppeteer 1.0
查看>>
.NET开源现状
查看>>
可替换元素和非可替换元素
查看>>
2016/08/25 The Secret Assumption of Agile
查看>>
(Portal 开发读书笔记)Portlet间交互-PortletSession
查看>>
搭建vsftpd服务器,使用匿名账户登入
查看>>
AMD改善Linux驱动,支持动态电源管理
查看>>
JAVA中循环删除list中元素的方法总结
查看>>
Java虚拟机管理的内存运行时数据区域解释
查看>>
人人都会深度学习之Tensorflow基础快速入门
查看>>
ChPlayer播放器的使用
查看>>
js 经过修改改良的全浏览器支持的软键盘,随机排列
查看>>
Mysql读写分离
查看>>
Oracle 备份与恢复学习笔记(5_1)
查看>>
Oracle 备份与恢复学习笔记(14)
查看>>
分布式配置中心disconf第一部(基本介绍)
查看>>
Scenario 9-Shared Uplink Set with Active/Active uplink,802.3ad(LACP)-Flex-10
查看>>
UML类图中的六种关系
查看>>