据预测,大约在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
6 1 3 9 1 11 7 5 7 13 5 4 4
Sample Output
4
解题思路:刚开始接触二分图染色和最大点独立集,这个题二分图染色就能做,因为保证了另外一个星系也是一个最大点独立集,所以直接染色,染色结果如果可行就把每个每个互不相干的集合(在染色的时候,有些时候不能从一个点到所有点,是因为有些点之间可以是同一集合也有可能是对立集合)里取两种颜色里的最大个数,然后相加。
下面代码是最大点独立集算法(其实在染色后就可以判断出)
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstdlib>
#include <cstring>
using namespace std;
vector<int>g[50010];
int n;
int color[50010];
struct node
{
int x,y;
}nod[50010];
bool dfs(int v,int c)
{
color[v]=c;
int SIZE=g[v].size();
for(int i=0;i<SIZE;i++)
{
int u=g[v][i];
if(color[u]==c) return false;
if(color[u]==0&&!dfs(u,-c))return false;
}
return true;
}
bool solve()
{
for(int i=1;i<=n;i++)//默认从1开始
{
if(color[i]==0)
{
if(!dfs(i,1))
{
return false;
}
}
}
return true;
}
bool used[50010];
int match[50010];
bool ddfs(int v)
{
used[v]=true;
int SIZE=g[v].size();
for(int i=0;i<SIZE;i++)
{
int u=g[v][i];
int w=match[u];
if(w<0||(!used[w]&&ddfs(w)))
{
match[u]=v;
match[v]=u;
return true;
}
}
return false;
}
int matching()
{
int res=0;
memset(match,-1,sizeof(match));
for(int v=1;v<=n;v++)
{
if(match[v]<0)
{
memset(used,0,sizeof(used));
if(ddfs(v))res++;
}
}
return res;
}
int main()
{
int i,j;
while(~scanf("%d",&n))
{
for(i=0;i<=n;i++) g[i].clear();
memset(color,0,sizeof(color));
for(i=1;i<=n;i++)
{
scanf("%d %d",&nod[i].x,&nod[i].y);
}
for(i=1;i<=n;i++)
{
for(j=i+1;j<=n;j++)
{
int x1=nod[i].x;
int x2=nod[j].x;
int y1=nod[i].y;
int y2=nod[j].y;
if((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)<=25)
{
g[i].push_back(j);
g[j].push_back(i);
}
}
}
if(!solve())
{
printf("-1\n");
}
else
{
printf("%d\n",n-matching());
}
}
return 0;
}
下面的是直接二分图染色
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstdlib>
#include <cstring>
using namespace std;
vector<int>g[50010];
int n;
int color[50010];
int n0,n1,sum;
struct node
{
int x,y;
}nod[50010];
bool dfs(int v,int c)
{
if(c==1) n1++;
else n0++;
color[v]=c;
int SIZE=g[v].size();
for(int i=0;i<SIZE;i++)
{
int u=g[v][i];
if(color[u]==c) return false;
if(color[u]==0&&!dfs(u,-c))return false;
}
return true;
}
bool solve()
{
for(int i=1;i<=n;i++)//默认从1开始
{
if(color[i]==0)
{
n0=0;n1=0;
if(!dfs(i,1))
{
return false;
}
sum+=max(n0,n1);
}
}
return true;
}
int main()
{
int i,j;
while(~scanf("%d",&n))
{
for(i=0;i<=n;i++) g[i].clear();
memset(color,0,sizeof(color));
for(i=1;i<=n;i++)
{
scanf("%d %d",&nod[i].x,&nod[i].y);
}
for(i=1;i<=n;i++)
{
for(j=i+1;j<=n;j++)
{
int x1=nod[i].x;
int x2=nod[j].x;
int y1=nod[i].y;
int y2=nod[j].y;
if((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)<=25)
{
g[i].push_back(j);
g[j].push_back(i);
}
}
}
sum=0;
if(!solve())
{
printf("-1\n");
}
else
{
printf("%d\n",sum);
}
}
return 0;
}