E - 食物链 POJ - 1182(并查集)

食物链 POJ - 1182

动物王国中有三类动物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 7
1 101 1
2 1 2
2 2 3
2 3 3
1 1 3
2 3 1
1 5 5
Sample Output
3

这个题有点毒,说句实话真的好难,在网上找个好久的题解,这个题又两种题解,第一种的话是带权并查集不过路径压缩算法公式和合并算法公式要自己推,我只看懂了第一个路径压缩算法公式推导,第二个实在是神一般的操作。然后看了一下第二种解法,我也是一脸懵逼,不过我看了好久,终于大概知道它的思路了:
题目不是输入的d要么是1要么是2,代表要么是同类,要么x吃y,然后它就是根据这个关系来维护并查集,不过和我们的思维有点不一样,我们一般会维护这由x,y,z组成的n个节点,然后大佬的思维就是将这n个节点扩展成3n个节点,然后维护它,一开始我是不理解为什么要扩展成3n个,为什么不是2n,4n个,因为题目只给出3类动物,所以在查询的时候,3n就可以覆盖所有节点了,(就是可以将三个种类并起来,如果是n的话并起来可以,但是就没有种类的那种关系了),然后有了三个种类,我们就可以确定关系了,题目给出的两种关系,同类或者是x吃y的关系,嗯。。。。我们可以这样,因为有了这样一个3n的空间我们可以自己定义同类关系,我们将 parent[x]==y,parent[x+n]==y+n,parent[x+2n]= y+2n, 这样一个一一对应关系定义为同类关系,然后我们可以再定义一个x吃y的关系,parent[x]=y+n,parent[x+n]=y+2n,parent[x+n*2]=y;
在这里插入图片描述
然后定义好了这两个关系后,我把程序的思路整理一下:
输入 n,k;(n是节点数,也就是三种类型动物的编号,k是k句询问)

for i=0 to k
输入 d,x,y;//x吃y
if (x>n||y>n||(d2&&xy))ans++;这是另外两种假话的情况这个比较简单;
if(d==1)
考虑这句话为假话的情况只有在已有的关系中,x吃y,或者y吃x,那么他们一定不是同类,那么这句话就是假话,记住是在已经存在的关系中判断,一开始的话默认是对的,因为这个关系图还没有建好,题目假设前面的话是对的来判断后面的话。
否则就是关系还没建立,或者这句话是真话,那么我们建立关系图。
parent[x]==y,parent[x+n]y+n,parent[x+2n]==y+2n,将这些点合并就行了。
if(d
2)
考虑这句话为假话的情况只有:x和y是同类或者y吃x,否则这句话是真话,我们建图。
第二种方法我还是有点懵再花点时间看一下。。。
ac代码:

#include<iostream>
using namespace std;
const int maxn=50000+10;

int parent[maxn*3];

int find_x(int x){
	if(x!=parent[x]){
		parent[x]=find_x(parent[x]);
	}
	return parent[x];
}

void ufs(int x,int y){
	int a=find_x(x);
	int b=find_x(y);
	if(a!=b){
		parent[a]=b;
	}
}

int main()
{
	int ans=0;
	int n,k;
	int d,x,y;
	scanf("%d %d",&n,&k);
	for(int i=1;i<=3*n;i++){
		parent[i]=i;
	} 
	for(int i=0;i<k;i++){
		scanf("%d %d %d",&d,&x,&y);
		if((x>n||y>n)||(d==2&&x==y)){
			ans++;
		}else if(d==1){
			if((find_x(y)==find_x(x+n))||(find_x(x)==find_x(y+n)))//如果y吃x,或者x吃y,则说明当前说的是假话 
			ans++;
			else{
				ufs(x,y);
				ufs(x+n,y+n);
				ufs(x+2*n,y+2*n);
			}
		}else if(d==2){
			//x吃y 
			if((find_x(x)==find_x(y))||(find_x(x)==find_x(y+2*n))){//x与y是同种类型或者y吃x,说明当前说的是假话 
				ans++; 
			}else{
				ufs(x,y+n);
				ufs(x+n,y+2*n);
				ufs(x+2*n,y);
			}
		}
	}
	printf("%d\n",ans);
}

参考文献:
https://blog.csdn.net/weixin_42488861/article/details/97621286
https://blog.csdn.net/niushuai666/article/details/6981689
https://www.cnblogs.com/zhuanzhuruyi/p/5863738.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
使用 JavaScript 编写的记忆游戏(附源代码)   项目:JavaScript 记忆游戏(附源代码) 记忆检查游戏是一个使用 HTML5、CSS 和 JavaScript 开发的简单项目。这个游戏是关于测试你的短期 记忆技能。玩这个游戏 时,一系列图像会出现在一个盒子形状的区域 。玩家必须找到两个相同的图像并单击它们以使它们消失。 如何运行游戏? 记忆游戏项目仅包含 HTML、CSS 和 JavaScript。谈到此游戏的功能,用户必须单击两个相同的图像才能使它们消失。 点击卡片或按下键盘键,通过 2 乘 2 旋转来重建鸟儿对,并发现隐藏在下面的图像! 如果翻开的牌面相同(一对),您就赢了,并且该对牌将从游戏消失! 否则,卡片会自动翻面朝下,您需要重新尝试! 该游戏包含大量的 javascript 以确保游戏正常运行。 如何运行该项目? 要运行此游戏,您不需要任何类型的本地服务器,但需要浏览器。我们建议您使用现代浏览器,如 Google Chrome 和 Mozilla Firefox, 以获得更好、更优化的游戏体验。要玩游戏,首先,通过单击 memorygame-index.html 文件在浏览器打开游戏。 演示: 该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软件,可能会出现误报的情况,源码本身并无病毒,使用源码时可以关闭360,或者添加信任。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值