洛谷 P2078 朋友

 

思路是分为两个并查集,然后计算下男女人数,然后直接比较,选小的

代码写的有点麻烦好像,交上去也没过,虽然结果对了

其实第一遍已经发现有问题了,因为比较的时候不小心把小于号打成大于号,然后就输出了朋友较多的男方,但是结果居然是5,交上去果然错了,后面第二遍代码就继续试了下男方,是对的,3,但是交上去还是unexpected 30.

想想好像是要考虑负号,毕竟数组没有a[-1],改成了

combine_2(abs(x2),abs(y2));

加了绝对值,交上去还是错的,有点烦了

实在想不出有什么错的,几分钟以后,我无聊画了个图,哦豁,我突然发现人家男女不一定是朋友啊,因为小明小红是朋友,但如果有一方结成了n对朋友,但那一坨人就是和小明不是朋友,那用cnt计数是不作效的,到头来也只有一对,所以记完数还要确保他们两坨人里面有小明和小红,否则就只有一对。第三次,我又双叒叕没过,还是只对三个测试点,明明测试了好多种情况都没问题了。 

洗完澡回来,过了很久很久。。我又意识到如果关系连接,就是相当于集合合并的时候,cnt计数+1,但是只检查1或-1在不在里面是不够的,如果有好几个大集合,但是他们没有合并,但是每回小集合合并成大集合的时候cnt都有+1,所以如果只有某一个或者几个大集合和1合并了是不行的,那样cnt所统计的是所有大集合里的人数(也包括不存在1的大集合)。那么还是得回到根节点写代码啊。

重新理下思路:

1.还是分为两个并查集,先把关系连接;

2.再从两个根节点出发,遍历查找各有多少个结点;

3.比较结点个数,输出较小的。


这里,由于连接的时候并不是按理想的方式连的,所以他们的根节点不一定是1
那还是得查找该元素所在的集合里有没有1
那就重新写个find函数

下面就是统计个数的一段代码,其余部分代码很简单,照着并查集的模板抄就可以了

    //从两个根节点开始遍历,统计所含节点个数
	//不对,根节点不一定是1,找1的根节点,然后统计根节点和1的根节点相同的数的个数 
	root=find(1,0);
	for(int i=2;i<=N;i++)
	{
		int k=find(i,0);
		if(k == root) cnt_1++;
	}
	root=find(1,1);//因为用过绝对值函数,所以不是从-1而是从1开始找 
	for(int i=2;i<=M;i++)
	{
		int k=find(i,1);
		if(k == root) cnt_2++;
	}
	
	if(cnt_1>cnt_2) cout<<cnt_2;
	else cout<<cnt_1;

//上面是主函数内的内容
//下面是find函数

int find(int x,int k)
{
	int x_root=x;
	while(parent[x_root][k]!=0)
	{
		x_root=parent[x_root][k];
	}
	return x_root;//递归找根 
}

最开始的时候也不知道怎么想的,改了四个小时多,人都傻了。

下次想清楚再写,不要又是编译错误交上去没过再来删删改改,洗完澡回来思路清楚了重新写一下虽然也还是有点小问题,但是稍微改改就过了。之前没想清楚就做,脑子一片混乱的,漏这漏那,就忽略了好多条件和特殊情况,考虑不全面。

以后做题思路:

1.想清楚用什么方法,要用到哪些方面的算法什么的

2.高屋建瓴,模块化思维,这个还是用的不错,函数用的挺多的,东西没有全挤在主函数里

3.要着重注意哪里,哪个细节或者是哪个题目的操作条件什么的,细节理不清就画图!画图真的有用

4.考虑特殊情况

第一次:unexpected 30

#include<iostream>
using namespace std;

#define MAX_TREE_SIZE 20010
int parent_1[MAX_TREE_SIZE]={0};
int deep_1[MAX_TREE_SIZE]={0};
int parent_2[MAX_TREE_SIZE]={0};
int deep_2[MAX_TREE_SIZE]={0};
int cnt_1=1,cnt_2=1;//一开始有小明和小红 
void initial(int n)
{
	for(int i=0;i<n;i++)
	{
		parent_1[i]=0;
		deep_1[i]=0;
		parent_2[i]=0;
		deep_2[i]=0;
	}
}

int find_root_1(int x)
{
	int x_root=x;
	while(parent_1[x_root]!=0)
	{
		x_root=parent_1[x_root];
	}
	return x_root;
}

void combine_1(int x,int y)
{
	int x_root=find_root_1(x);
	int y_root=find_root_1(y);
	if(x_root!=y_root)
	{
		if(deep_1[x_root]>deep_1[y_root])
		{
			parent_1[y_root]=x_root;
		}
		else if(deep_1[x_root]<deep_1[y_root])
		{
			parent_1[x_root]=y_root;
		}
		else
		{
			parent_1[x_root]=y_root;
			deep_1[y_root]++;
		}
	}
	cnt_1++;
}

int find_root_2(int x)
{
	int x_root=x;
	while(parent_2[x_root]!=0)
	{
		x_root=parent_2[x_root];
	}
	return x_root;
}

void combine_2(int x,int y)
{
	int x_root=find_root_2(x);
	int y_root=find_root_2(y);
	if(x_root!=y_root)
	{
		if(deep_2[x_root]>deep_2[y_root])
		{
			parent_2[y_root]=x_root;
		}
		else if(deep_2[x_root]<deep_2[y_root])
		{
			parent_2[x_root]=y_root;
		}
		else
		{
			parent_2[x_root]=y_root;
			deep_2[y_root]++;
		}
		cnt_2++;
	}
}

int main()
{
	int N,M,P,Q;//A公司有N名员工,其中有P对朋友关系。B公司有M名员工,其中有Q对朋友关系
	cin>>N>>M>>P>>Q;
	
	int x1,y1;
	for(int i=0;i<P;i++)
	{
		cin>>x1>>y1;
		combine_1(x1,y1);
	}
	int x2,y2;
	for(int i=0;i<Q;i++)
	{
		cin>>x2>>y2;
		combine_2(x2,y2);
	}
	
	if(cnt_1>cnt_2)
	{
		cout<<cnt_2;
	}
	else
	{
		cout<<cnt_1;
	}
}

第二次:unexpected 30

#include<iostream>
using namespace std;

#define MAX_TREE_SIZE 20010
int parent_1[MAX_TREE_SIZE]={0};
int deep_1[MAX_TREE_SIZE]={0};
int parent_2[MAX_TREE_SIZE]={0};
int deep_2[MAX_TREE_SIZE]={0};
int cnt_1=1,cnt_2=1;//一开始有小明和小红 
void initial(int n)
{
	for(int i=0;i<n;i++)
	{
		parent_1[i]=0;
		deep_1[i]=0;
		parent_2[i]=0;
		deep_2[i]=0;
	}
}

int find_root_1(int x)
{
	int x_root=x;
	while(parent_1[x_root]!=0)
	{
		x_root=parent_1[x_root];
	}
	return x_root;
}

void check_1(int x,int y)
{
	int x_root=find_root_1(x);
	int y_root=find_root_1(y);
	if(x_root!=y_root) cnt_1++;
}

void combine_1(int x,int y)
{
	check_1(x,y);
	//结成朋友就直接+1不行,因为朋友的朋友也是朋友,所以要先检查一下两人是否已在同一集合
	int x_root=find_root_1(x);
	int y_root=find_root_1(y);
	if(x_root!=y_root)
	{
		if(deep_1[x_root]>deep_1[y_root])
		{
			parent_1[y_root]=x_root;
		}
		else if(deep_1[x_root]<deep_1[y_root])
		{
			parent_1[x_root]=y_root;
		}
		else
		{
			parent_1[x_root]=y_root;
			deep_1[y_root]++;
		}
	}
}

int find_root_2(int x)
{
	int x_root=x;
	while(parent_2[x_root]!=0)
	{
		x_root=parent_2[x_root];
	}
	return x_root;
}

void check_2(int x,int y)
{
	int x_root=find_root_2(x);
	int y_root=find_root_2(y);
	if(x_root!=y_root) cnt_2++;
}

void combine_2(int x,int y)
{
	check_2(x,y);
	int x_root=find_root_2(x);
	int y_root=find_root_2(y);
	if(x_root!=y_root)
	{
		if(deep_2[x_root]>deep_2[y_root])
		{
			parent_2[y_root]=x_root;
		}
		else if(deep_2[x_root]<deep_2[y_root])
		{
			parent_2[x_root]=y_root;
		}
		else
		{
			parent_2[x_root]=y_root;
			deep_2[y_root]++;
		}
	}
}

int main()
{
	int N,M,P,Q;//A公司有N名员工,其中有P对朋友关系。B公司有M名员工,其中有Q对朋友关系
	cin>>N>>M>>P>>Q;
	
	int x1,y1;
	for(int i=0;i<P;i++)
	{
		cin>>x1>>y1;
		combine_1(x1,y1);
	}
	int x2,y2;
	for(int i=0;i<Q;i++)
	{
		cin>>x2>>y2;
		combine_2(x2,y2);
	}
	
	if(cnt_1>cnt_2)
	{
		cout<<cnt_2;
	}
	else
	{
		cout<<cnt_1;
	}

第三次:

#include<iostream>
#include<cmath>
using namespace std;

#define MAX_TREE_SIZE 20010
int parent_1[MAX_TREE_SIZE]={0};
int deep_1[MAX_TREE_SIZE]={0};
int parent_2[MAX_TREE_SIZE]={0};
int deep_2[MAX_TREE_SIZE]={0};
int cnt_1=1,cnt_2=1;//一开始有小明和小红 
int checkkk=1;//确保小明小红都在集合里 
int x1_root,x2_root;//男女并查集的根结点 
void initial(int n)
{
	for(int i=0;i<n;i++)
	{
		parent_1[i]=0;
		deep_1[i]=0;
		parent_2[i]=0;
		deep_2[i]=0;
	}
}

int find_root_1(int x)
{
	int x_root=x;
	while(parent_1[x_root]!=0)
	{
		x_root=parent_1[x_root];
	}
	return x_root;
}

void check_1(int x,int y)
{
	int x_root=find_root_1(x);
	int y_root=find_root_1(y);
	if(x_root!=y_root) cnt_1++;
}

void combine_1(int x,int y)
{
	check_1(x,y);
	//结成朋友就直接+1不行,因为朋友的朋友也是朋友,所以要先检查一下两人是否已在同一集合
	int x_root=find_root_1(x);
	int y_root=find_root_1(y);
	if(x_root!=y_root)
	{
		if(deep_1[x_root]>deep_1[y_root])
		{
			parent_1[y_root]=x_root;
		}
		else if(deep_1[x_root]<deep_1[y_root])
		{
			parent_1[x_root]=y_root;
		}
		else
		{
			parent_1[x_root]=y_root;
			deep_1[y_root]++;
		}
	}
	x1_root=x_root;
}

int find_root_2(int x)
{
	int x_root=x;
	while(parent_2[x_root]!=0)
	{
		x_root=parent_2[x_root];
	}
	return x_root;
}

void check_2(int x,int y)
{
	int x_root=find_root_2(x);
	int y_root=find_root_2(y);
	if(x_root!=y_root) cnt_2++;
}

void combine_2(int x,int y)
{
	check_2(x,y);
	int x_root=find_root_2(x);
	int y_root=find_root_2(y);
	if(x_root!=y_root)
	{
		if(deep_2[x_root]>deep_2[y_root])
		{
			parent_2[y_root]=x_root;
		}
		else if(deep_2[x_root]<deep_2[y_root])
		{
			parent_2[x_root]=y_root;
		}
		else
		{
			parent_2[x_root]=y_root;
			deep_2[y_root]++;
		}
	}
	x2_root=x_root;
}

void check(int xiaoming,int x1_root,int xiaohong,int x2_root)
{
	int x_root,y_root;
	x_root=find_root_1(xiaoming);
	y_root=find_root_1(x1_root);
	if(x_root!=y_root)
		 checkkk=0;
	x_root=find_root_1(xiaohong);
	y_root=find_root_1(x2_root);
	if(x_root!=y_root)
		 checkkk=0;
}

int main()
{
	int N,M,P,Q;
	//A公司有N名员工,其中有P对朋友关系
	//B公司有M名员工,其中有Q对朋友关系
	cin>>N>>M>>P>>Q;
	
	int x,y;
	for(int i=0;i<P;i++)//将A公司P对关系结合 
	{
		cin>>x>>y;
		combine_1(x,y);
	}
	for(int i=0;i<Q;i++)//将B公司Q对关系结合 
	{
		cin>>x>>y;
		combine_2(abs(x),abs(y));
	}
	
	check(1,x1_root,abs(-1),x2_root);//检查两堆人里是否小明小红都在,小明小红起桥梁作用
	
	if(checkkk==1)
	{
		if(cnt_1>cnt_2)
		{
			cout<<cnt_2;
		}
		else
		{
			cout<<cnt_1;
		}
	}
	else
	{
		cout<<"1";
	}
}

AC代码:

#include<iostream>
#include<cmath>
using namespace std;

#define MAX_TREE_SIZE 20010
int parent[MAX_TREE_SIZE][2]={0};
int deep[MAX_TREE_SIZE]={0};

//把两个并查集先整理好 
int find_root_1(int x);
void combine_1(int x,int y);
int find_root_2(int x);
void combine_2(int x,int y);
int find(int x,int k);

int cnt_1=1,cnt_2=1,root;//已知小明和小红,至少有一对 

int main()
{
	int N,M,P,Q;
	//A公司有N名员工,其中有P对朋友关系
	//B公司有M名员工,其中有Q对朋友关系
	cin>>N>>M>>P>>Q;
	
	int x,y;
	void initial_1(int n);
	for(int i=0;i<P;i++)//将A公司P对关系结合
	{
		cin>>x>>y;
		combine_1(x,y);
	}
	void initial_2(int n);
	for(int i=0;i<Q;i++)//将B公司Q对关系结合 
	{
		cin>>x>>y;
		combine_2(abs(x),abs(y));
	}
	
	//从两个根节点开始遍历,统计所含节点个数
	//不对,根节点不一定是1,找1的根节点,然后统计根节点和1的根节点相同的数的个数 
	root=find(1,0);
	for(int i=2;i<=N;i++)
	{
		int k=find(i,0);
		if(k == root) cnt_1++;
	}
	root=find(1,1);//因为用过绝对值函数,所以不是从-1而是从1开始找 
	for(int i=2;i<=M;i++)
	{
		int k=find(i,1);
		if(k == root) cnt_2++;
	}
	
	if(cnt_1>cnt_2) cout<<cnt_2;
	else cout<<cnt_1;
}

int find(int x,int k)
{
	int x_root=x;
	while(parent[x_root][k]!=0)
	{
		x_root=parent[x_root][k];
	}
	return x_root;//递归找根 
}

void initial_1(int n)
{
	for(int i=0;i<n;i++)
	{
		parent[i][0]=0;
		deep[i]=0;
	}
}

int find_root_1(int x)
{
	int x_root=x;
	while(parent[x_root][0]!=0)
	{
		x_root=parent[x_root][0];
	}
	return x_root;
}

void combine_1(int x,int y)
{
	int x_root=find_root_1(x);
	int y_root=find_root_1(y);
	if(x_root!=y_root)
	{
		if(deep[x_root]>deep[y_root])
		{
			parent[y_root][0]=x_root;
		}
		else if(deep[x_root]<deep[y_root])
		{
			parent[x_root][0]=y_root;
		}
		else
		{
			parent[x_root][0]=y_root;
			deep[y_root]++;
		}
	}
}

void initial_2(int n)
{
	for(int i=0;i<n;i++)
	{
		parent[i][1]=0;
		deep[i]=0;
	}
}

int find_root_2(int x)
{
	int x_root=x;
	while(parent[x_root][1]!=0)
	{
		x_root=parent[x_root][1];
	}
	return x_root;
}

void combine_2(int x,int y)
{
	int x_root=find_root_2(x);
	int y_root=find_root_2(y);
	if(x_root!=y_root)
	{
		if(deep[x_root]>deep[y_root])
		{
			parent[y_root][1]=x_root;
		}
		else if(deep[x_root]<deep[y_root])
		{
			parent[x_root][1]=y_root;
		}
		else
		{
			parent[x_root][1]=y_root;
			deep[y_root]++;
		}
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值