星系碰撞 FZU - 2194

据预测,大约在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;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值