poj2236 并查集第一题 思路分析

并查集第一题 思路分析 poj2236

开始训练并查集 这是做并查集第一题 所以做一个思路分析 有助于自己对并查集的理解

题意就不解释了

问题一 判断各个节点之间是否可达?

很明显 这里可以用dfs 或者 并查集 进行判断 这里用并查集比较快 因为这里并不用用到两点之间的路劲(由于比较慢,所以不用路劲来进行解决)或者其他一些信息

一开始做的时候 因为是先进行各个点之间用并查集单独进行连通 到了后面的修复操作就不知道该怎样在并查集中进行修复操作 如果节点的修复操作设为true 就代表这个节点可以被这个节点所在的集合中的其他节点直接访问 但是一个集合的节点在原图中可以是间接相连的,所以上面的操作就是有问题的 

问题二 修复操作在上面的并查集中该怎样做?

上面是先判断可达在就行修复,这个是有问题的,其实是反过来做,先进行修复操作,然后再根据修复的节点,便利之前所操作的节点,看是是否可达,如果可达就说明集合中的任何节点都与这个节点相互连通,既可以测试成功,就加入这个节点到集合中

总结 

是先确定修复 在建立并查集 从这个便可以看出 要先确定元素中的关系才用并查集维护关系 而并查集中的元素是相互可达的 只有这样的关系才能加入并查集 因为是第一次做并查集 所以这道题想了很久 一开始的思路就错了 导致后面的都错了 看来并查集应用的思想自己还没弄懂 得要多思考 多换角度想啊

 
#include <cstdio>
#include <cstring>
#include <math.h>
#include <algorithm>
using namespace std;
#define INF 0xfffffff//跑了3000多秒 有点慢 这里询问是300000 所以在计算两点之间距离时 
int N,D,x,y;//花费了很多的时间 可以用个预处理处理二维数组存储距离 
struct node{
	bool rep;
	int x,y;
}mp[1005];int pa[1005];
double distants(node a,node b)
{
	return sqrt((double)(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int findset(int x)
{
	return pa[x]==x?x:pa[x]=findset(pa[x]);//带路径压缩
}
int unite(int x,int y)
{
	int px=findset(x);
	int py=findset(y);
	if(px!=py)
		if(distants(mp[x],mp[y])<=(double)D)
			pa[py]=px;
}
int main()
{
	char op;
	scanf("%d%d",&N,&D);
	for(int i=1;i<=N;i++)
	{
		pa[i]=i;
		scanf("%d%d",&mp[i].x,&mp[i].y);
		mp[i].rep=false;
	}
	while(scanf(" %c",&op)!=EOF)
	{
		int a,b;
		if(op=='O')
		{
			scanf("%d",&a);
			mp[a].rep=true;
			for(int i=1;i<=N;i++)
			{
				if(i!=a && mp[i].rep==true)
					unite(i,a);
			}
		}
		else
		{
			scanf("%d%d",&a,&b);
			if(findset(a)==findset(b))
				printf("SUCCESS\n");
			else
				printf("FAIL\n");
		}
	}
	return 0;
 } 

第二种

#include <cstdio>
#include <cstring>
#include <math.h>
#include <algorithm>
using namespace std;
#define INF 0xfffffff//好像没快多少
int N,D,x,y;//
struct node{
	bool rep;
	int x,y;
}mp[1005];int pa[1005];
double dist[1005][1005];  
double distants(node a,node b)
{
	return sqrt((double)(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int findset(int x)
{
	return pa[x]==x?x:pa[x]=findset(pa[x]);//路劲压缩
}
int unite(int x,int y)
{
	int px=findset(x);
	int py=findset(y);
	if(px!=py)
		if(dist[x][y]<=(double)D)
			pa[py]=px;
}
int main()
{
	char op;
	scanf("%d%d",&N,&D);
	for(int i=1;i<=N;i++)
	{
		pa[i]=i;
		scanf("%d%d",&mp[i].x,&mp[i].y);
		mp[i].rep=false;
	}
	for(int i=1;i<=N;i++)
	{
		for(int j=i-1;j>=1;j--)
		{
			dist[i][j]=distants(mp[i],mp[j]);
			dist[j][i]=dist[i][j];
		}
	}
	while(scanf(" %c",&op)!=EOF)
	{
		int a,b;
		if(op=='O')
		{
			scanf("%d",&a);
			mp[a].rep=true;
			for(int i=1;i<=N;i++)
			{
				if(i!=a && mp[i].rep==true)
					unite(i,a);
			}
		}
		else
		{
			scanf("%d%d",&a,&b);
			if(findset(a)==findset(b))
				printf("SUCCESS\n");
			else
				printf("FAIL\n");
		}
	}
	return 0;
 } 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值