思路是分为两个并查集,然后计算下男女人数,然后直接比较,选小的
代码写的有点麻烦好像,交上去也没过,虽然结果对了
其实第一遍已经发现有问题了,因为比较的时候不小心把小于号打成大于号,然后就输出了朋友较多的男方,但是结果居然是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]++;
}
}
}