zoj 3761 Easy billiards 并查集+dfs

生活真是奇妙的东西,这样的题目居然能被联想到这样的算法,只能说智商不够啊。

这道题目的意思不解释了,月赛的时候我队友已经想出来了做法,但是我们最后还是没A。


题解:

1。首先将所有能连接的球连接起来,然后看这个图有几个连通分量,那最后就会剩下几个球,这个用并查集实现下就好了。

由于xi,yi坐标比较分散所以要用邻接表进行存储。

2. 接下来就是输出方案,本来我们是想考虑点的度的,后来发现实现起来有点困难,实际上只需要按照并查集的唯一的头,进行深度优先搜索,这样就形成了一颗深搜树,

然后再用叶子节点打他的根节点就可以了。这样一次能打掉所有叶子节点(简直神奇)。

3.一开始进行2次排序,进行点的连接。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int e,head[10005],root[10005],vis[10005];
struct node
{
	int x,y;
	int nod,l;
}s[10005],q[10005];

struct lj
{
	int v;
	int next;
}nn[10005];
int cmp1(struct node a,struct node b)
{
	if(a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}

int cmp2(struct node a,struct node b)
{
	if(a.y==b.y) return a.x<a.x;
	return a.y<b.y;
}

void link(int u,int v)
{
	nn[e].v=v;
	nn[e].next=head[u];
	head[u]=e++;
}

int find(int x)
{
	if(x==root[x]) return x;
	else return root[x]=find(root[x]);
}

void dfs(int x)
{
	int k;
	for(k=head[x];k!=-1;k=nn[k].next){
		int v=nn[k].v;
		if(!vis[v]){
				vis[v]=1;
				if(q[v].x==q[x].x){
					if(q[v].y<q[x].y)
						q[v].l=4;
					else
						q[v].l=3;
				}
				if(q[v].y==q[x].y){
					if(q[v].x<q[x].x)
						q[v].l=2;
					else
						q[v].l=1;
				}
				dfs(v);
		}
	}
	if(q[x].l==4) printf("(%d, %d) UP\n",q[x].x,q[x].y);
	else if(q[x].l==3) printf("(%d, %d) DOWN\n",q[x].x,q[x].y);
	else if(q[x].l==2) printf("(%d, %d) RIGHT\n",q[x].x,q[x].y);
	else if(q[x].l==1) printf("(%d, %d) LEFT\n",q[x].x,q[x].y);
}

int main()
{
	int n,i;
	while(scanf("%d",&n)!=EOF){
		e=1;
		memset(head,-1,sizeof(head));
		for(i=0;i<n;i++){
			scanf("%d %d",&s[i].x,&s[i].y);
			q[i].x=s[i].x;q[i].y=s[i].y;
			q[i].nod=s[i].nod=i;
			q[i].l=s[i].l=-1;
		}
		memset(vis,0,sizeof(vis));
		for(i=0;i<n;i++) root[i]=i;
		sort(s,s+n,cmp1);
		for(i=1;i<n;i++){
			if(s[i].x==s[i-1].x){
				link(s[i].nod,s[i-1].nod);
				link(s[i-1].nod,s[i].nod);
				int ra=find(s[i].nod);
				int rb=find(s[i-1].nod);
				if(ra!=rb) root[rb]=ra;
			}
		}
		sort(s,s+n,cmp2);
		for(i=1;i<n;i++){
			if(s[i].y==s[i-1].y){
				link(s[i].nod,s[i-1].nod);
				link(s[i-1].nod,s[i].nod);
				int ra=find(s[i].nod);
				int rb=find(s[i-1].nod);
				if(ra!=rb) root[rb]=ra;
			}
		}
		int ans=0,father[3000];
		for(i=0;i<n;i++){
			if(root[i]==i){
				father[ans++]=i;
			}
		}
		printf("%d\n",ans);
		for(i=0;i<ans;i++){
			vis[father[i]]=1;
			dfs(father[i]);
		}
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值