FZU - 2194 星系碰撞

Problem 2194 星系碰撞

Accept: 29    Submit: 102
Time Limit: 30000 mSec    Memory Limit : 327680 KB

Problem Description

据预测,大约在100亿年后,狮子座星系将与银河系发生碰撞,两个星系的碰撞将会合并两个星系,但是没有2个星球会相撞。现在某科学家得到两个星系合并后的结果,一些二维平面上的点,但是不知道那些星球属于银河系,已知如果两个星球属于同一个星系,那么他们之间的距离大于5光年,这边的距离指的是欧几里得距离,即(x1,y1)与(x2,y2)的距离为sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))。现在想请你帮忙把合并后的结果分成2个集合,一个属于银河系,一个属于狮子座星系,由于集合划分的方案可能有多种,现在想知道最多有多少个星球可能属于银河系。(可以所有星球都属于银河系)

例如:如下图有6个点,你可以有以下4中划分{{1, 2, 4, 5}, {3, 6}}; {{1, 2, 3, 4}, {5, 6}}; {{1, 4,5}, {2, 3, 6}}; {{1, 3, 4}, {2, 5, 6}} ,那么可以采用第一种划分{1,2,4,5} 都属于银河系,答案为4.

Input

包含多组数据每组数据输入第一行 一个整数N 表示星球个数(1<=N<=50000),接下去N 行 每行2个整数 x和y 表示星球的坐标(1<=x,y<=500000),没有重合的点。

Output

输出一行一个整数表示最多有多少个星球属于银河系。如果没办法进行划分那么输出-1。

Sample Input

61 39 111 75 713 54 4

Sample Output

4


  一开始没看见是多组数据WA了好几发,原来用map做发现会T于是自己手写了个hash,二分图判断加染色,然后把几个连通分量中较大的一侧累加起来就是答案。
#include <cmath>
#include <cstring>
#include <cstdio>
#include <utility>
#include <iostream>
#include <algorithm>
using namespace std;
struct point
{
	long long x,y;
} a[50002];
struct v
{
	int num,next;
} b[5000000];
pair <int ,int> f[521373+50002];
bool flag;
int jud[521373+50002],val[521373+50002];
void Insert(pair <int ,int > x,int v)
{
	int k=(x.first%23333)*10+x.second%521373;
	while(jud[k] && f[k] != x) k++;
	jud[k]=1;
	f[k]=x;
	val[k]=v;
}
int find(pair <int ,int > x)
{
	int k=(x.first%23333)*10+x.second%521373;
	while(jud[k] && f[k] != x) k++;
	if(jud[k] == 0) return 0;
	return val[k];
}
int n,A[50002],col[50002],Tot,ans[3],Ans;
long long x,y;
void insert(int x,int y)
{
	Tot++;
	b[Tot].num=y;
	b[Tot].next=A[x];
	A[x]=Tot;
}
void dfs(int x)
{
	int k=A[x];
	while(k)
	{
		int j=b[k].num;
		if(col[j] == 0)
		{
			col[j]=3-col[x];
			ans[col[j]]++;
			dfs(j); 	
			if(flag) return;
		}
		else 
		 if(col[j] == col[x])
		 {
		 	flag=true;
		 	return ;
		 } 
		k=b[k].next;	
	}	
}
int main()
{
	cin.sync_with_stdio(false);
	while(cin>>n)
	{
		Tot=0,Ans=0;
		memset(A,0,sizeof(A));
		memset(col,0,sizeof(col));
		memset(jud,0,sizeof(jud));
		for(int i=1;i <= n;i++)
		{
			cin>>a[i].x>>a[i].y;
			Insert(make_pair(a[i].x,a[i].y),i);
		}
		for(int i=1;i <= n;i++)
		{
			for(x=a[i].x;x <= a[i].x+5;x++)
			 for(y=a[i].y-5;y <= a[i].y+5;y++)
			  if((x != a[i].x || y != a[i].y) && ((x-a[i].x)*(x-a[i].x)+(y-a[i].y)*(y-a[i].y) <= 25ll))
			   {
			    	int now=find(make_pair(x,y));
			    	if(now == 0) continue;
					insert(now,i);
					insert(i,now);	
			   } 		
		}
		flag=false;
		for(int i=1;i <= n;i++)
		 if(col[i] == 0)
		 {
		 	col[i]=1;
		 	ans[1]=ans[2]=0;
		 	ans[1]++;
			dfs(i);
			if(flag) break;
			Ans+=max(ans[1],ans[2]);
		 }
		 if(flag) 
		 {
		 	cout<<"-1"<<endl;
		 	continue;
		 }
		 cout<<Ans<<endl;
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值