【算法】食物链
/**
* https://www.acwing.com/problem/content/242/
* 动物王国中有三类动物 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 句话有的是真的,有的是假的。
* 当一句话满足下列三条之一时,这句话就是假话,否则就是真话。
* 当前的话与前面的某些真的话冲突,就是假话;
* 当前的话中 X 或 Y 比 N 大,就是假话;
* 当前的话表示 X 吃 X,就是假话。
* 你的任务是根据给定的 N 和 K 句话,输出假话的总数。
* 输入格式
* 第一行是两个整数 N 和 K,以一个空格分隔。
* 以下 K 行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中 D 表示说法的种类。
* 若 D=1,则表示 X 和 Y 是同类。
* 若 D=2,则表示 X 吃 Y。
* 输出格式
* 只有一个整数,表示假话的数目。
* 数据范围
* 1≤N≤50000,
* 0≤K≤100000
* 输入样例:
* 100 7
* 1 101 1
* 2 1 2
* 2 2 3
* 2 3 3
* 1 1 3
* 2 3 1
* 1 5 5
* 输出样例:
* 3
*
*/
思路:初始化n个集合,p[x] = x 为祖宗节点,祖宗节点的不同表示不同的集合。定义一个数组d,代表每个节点到祖宗节点的距离,d[x] mod 3 得到的结果0,1,2 表示不同的动物。对每个说法进行分析,如果说 x和y不在同一个集合,将x与y存入同一个集合中,根据符合题意的说法更新距离d[x]与d[y]。
实现代码:
public class Main {
public static int[] p = new int[50010];
public static int[] d = new int[50010];
public static int find(int x) {
//查找根节点+路径压缩 - 在查询父节点的时候,直接让x的父节点 = 祖宗节点,更新距离d
if (p[x] != x) {
int t = find(p[x]);
d[x] += d[p[x]];
p[x] = t;
}
return p[x];
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
for (int i = 1; i <= n; i++) {
p[i] = i;
}
int k = scanner.nextInt();
int res = 0;
while (k-- > 0) {
int opt = scanner.nextInt();
int x = scanner.nextInt();
int y = scanner.nextInt();
if (x > n || y > n) {
res++;
} else {
int px = find(x), py = find(y);
if (opt == 1) {
//在同一个集合里面就去判断是不是同类
if (px == py && (d[x] - d[y]) % 3 != 0) {
res++;
} else if (px != py) {
//不是同一个集合,按照说的话来进行构造
p[px] = py;
d[px] = d[y] - d[x];
}
} else {
//在同一个集合里面就去判断是不是x吃y
if (px == py && (d[x] - d[y] - 1) % 3 != 0) {
res++;
} else if (px != py) {
//不是同一个集合,按照说的话来进行构造
p[px] = py;
d[px] = d[y] - d[x] + 1;
}
}
}
}
System.out.println(res);
}
}