最小点覆盖

这里介绍的算法是,先任意选取两个点,以这两个点的连线为直径作圆。再以此判断剩余的点,看它们是否都在圆内(或圆上),如果都在,说明这个圆已经找到。如果没有都在:假设我们用的最开始的两个点为p[1],p[2],并且找到的第一个不在圆内(或圆上)的点为p[i],于是我们用这个点p[i]去寻找覆盖p[1]到p[i-1]的最小覆盖圆。

那么,过确定点p[i]的从p[1]到p[i-1]的最小覆盖圆应该如何求呢?

我们先用p[1]和p[i]做圆,再从2到i-1判断是否有点不在这个圆上,如果都在,则说明已经找到覆盖1到i-1的圆。如果没有都在:假设我们找到第一个不在这个圆上的点为p[j],于是我们用两个已知点p[j]与p[i]去找覆盖1到j-1的最小覆盖圆。

而对于两个已知点p[j]与p[i]求最小覆盖圆,只要从1到j-1中,第k个点求过p[k],p[j],p[i]三个点的圆,再判断k+1到j-1是否都在圆上,若都在,说明找到圆;若有不在的,则再用新的点p[k]更新圆即可。

于是,这个问题就被转化为若干个子问题来求解了。

由于三个点确定一个圆,我们的过程大致上做的是从没有确定点,到有一个确定点,再到有两个确定点,再到有三个确定点来求圆的工作。

关于正确性的证明以及复杂度的计算这里就不介绍了,可以去看完整的算法介绍:http://wenku.baidu.com/view/162699d63186bceb19e8bbe6.html

恩。关于细节方面。

a.通过三个点如何求圆?

先求叉积。

若叉积为0,即三个点在同一直线,那么找到距离最远的一对点,以它们的连线为直径做圆即可;

若叉积不为0,即三个点不共线,那么就是第二个问题,如何求三角形的外接圆?

b.如何求三角形外接圆?

假设三个点(x1,y1),(x2,y2),(x3,y3);

设过(x1,y1),(x2,y2)的直线l1方程为Ax+By=C,它的中点为(midx,midy)=((x1+x2)/2,(y1+y2)/2),l1中垂线方程为A1x+B1y=C1;则它的中垂线方程中A1=-B=x2-x1,B1=A=y2-y1,C1=-B*midx+A*midy=((x2^2-x1^2)+(y2^2-y1^2))/2;

同理可以知道过(x1,y1),(x3,y3)的直线的中垂线的方程。

于是这两条中垂线的交点就是圆心。

c.如何求两条直线交点?

设两条直线为A1x+B1y=C1和A2x+B2y=C2。

设一个变量det=A1*B2-A2*B1;

如果det=0,说明两直线平行;若不等于0,则求交点:x=(B2*C1 -B1*C2)/det,y=(A1*C2-A2*C1)/det;

d.于是木有了。。

恩。都讲清楚了。于是是代码:

#include<stdio.h>
#include<math.h>
struct   TPoint
{
         double x,y;
};
TPoint a[1005],d;
double r;

double   distance(TPoint   p1,   TPoint   p2)   //两点间距离
{
    return (sqrt((p1.x-p2.x)*(p1.x -p2.x)+(p1.y-p2.y)*(p1.y-p2.y)));
}
double multiply(TPoint   p1,   TPoint   p2,   TPoint   p0)
{
    return   ((p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y));
}
void MiniDiscWith2Point(TPoint   p,TPoint   q,int   n)
{
    d.x=(p.x+q.x)/2.0;
    d.y=(p.y+q.y)/2.0;
    r=distance(p,q)/2;
    int k;
    double c1,c2,t1,t2,t3;
    for(k=1;k<=n;k++)
    {
        if(distance(d,a[k])<=r)continue;
        if(multiply(p,q,a[k])!=0.0)
        {
            c1=(p.x*p.x+p.y*p.y-q.x*q.x-q.y*q.y)/2.0;
            c2=(p.x*p.x+p.y*p.y-a[k].x*a[k].x-a[k].y*a[k].y)/2.0;

            d.x=(c1*(p.y-a[k].y)-c2*(p.y-q.y))/((p.x-q.x)*(p.y-a[k].y)-(p.x-a[k].x)*(p.y-q.y));
            d.y=(c1*(p.x-a[k].x)-c2*(p.x-q.x))/((p.y-q.y)*(p.x-a[k].x)-(p.y-a[k].y)*(p.x-q.x));
            r=distance(d,a[k]);
        }
        else
        {
            t1=distance(p,q);
            t2=distance(q,a[k]);
            t3=distance(p,a[k]);
            if(t1>=t2&&t1>=t3)
            {d.x=(p.x+q.x)/2.0;d.y=(p.y+q.y)/2.0;r=distance(p,q)/2.0;}
            else if(t2>=t1&&t2>=t3)
            {d.x=(a[k].x+q.x)/2.0;d.y=(a[k].y+q.y)/2.0;r=distance(a[k],q)/2.0;}
            else
            {d.x=(a[k].x+p.x)/2.0;d.y=(a[k].y+p.y)/2.0;r=distance(a[k],p)/2.0;}
        }
    }
}

void MiniDiscWithPoint(TPoint   pi,int   n)
{
    d.x=(pi.x+a[1].x)/2.0;
    d.y=(pi.y+a[1].y)/2.0;
    r=distance(pi,a[1])/2.0;
    int j;
    for(j=2;j<=n;j++)
    {
    if(distance(d,a[j])<=r)continue;
        else
        {
            MiniDiscWith2Point(pi,a[j],j-1);
        }
    }
}
int main()
{
    int i,n;
    while(scanf("%d",&n)&&n)
    {
        for(i=1;i<=n;i++)
        {
            scanf("%lf %lf",&a[i].x,&a[i].y);
        }
        if(n==1)
        { printf("%.2lf %.2lf 0.00\n",a[1].x,a[1].y);continue;}
        r=distance(a[1],a[2])/2.0;
        d.x=(a[1].x+a[2].x)/2.0;
        d.y=(a[1].y+a[2].y)/2.0;
        for(i=3;i<=n;i++)
        {
            if(distance(d,a[i])<=r)continue;
            else
            MiniDiscWithPoint(a[i],i-1);
        }
        printf("%.2lf %.2lf %.2lf\n",d.x,d.y,r);
    }
    return 0;
}

  

时间: 2024-08-04 14:38:31

最小点覆盖的相关文章

UVA-11419 SAM I AM (最小点覆盖)

题目大意:在一个n*m的网格中,有k个目标,现在可以任选一行或列消除在其上的所有目标,求出最少选择次数及选法. 题目分析:经典的最小点覆盖问题,并且输出一个最小点覆盖集.在求出最大匹配之后,以未覆盖的x点进行标记,沿着未覆盖->覆盖->未覆盖->覆盖...的路径标记,最后x中未标记的和y中标记的点构成最小点覆盖集. 代码如下: # include<iostream> # include<cstdio> # include<cstring> # incl

hdu 1054 Strategic Game 二分图最小点覆盖

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1054 题意: 给出一个无向图,求最小点覆盖. 思路: 用网络流来做设立一个超级源点和一个超级汇点. 每个点拆成i和i'. 从超级源点向点i连一条边,容量为1. 从i’向超级汇点连一条边,容量为1. 从i向i'连一条边,容量为正无穷. 然后求最小割/2.因为拆点拆成了2个. 也可以用二分图匹配来做,也是求出最大匹配然后/2. 1 #include <bits/stdc++.h> 2 using na

POJ2226 Muddy Fields(二分图最小点覆盖集)

题目给张R×C的地图,地图上*表示泥地..表示草地,问最少要几块宽1长任意木板才能盖住所有泥地,木板可以重合但不能盖住草地. 把所有行和列连续的泥地(可以放一块木板铺满的)看作点且行和列连续泥地分别作为XY部,每一块泥地看作边.这样就构造出了一个二分图. 那么,问题就是在这个二分图中就是选出最少的点覆盖所有的边,即二分图最小点覆盖集,而二分图最小点覆盖集=二分图最大匹配. 1 #include<cstdio> 2 #include<cstring> 3 #include<qu

UVa11419 SAM I AM(构造最小点覆盖)

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=27475 [思路] 二分图的最小点覆盖以及构造最小覆盖. 可见:http://www.tuicool.com/articles/jmAnEb [代码] #include<cstdio> #include<cstring> #include<vector> #include<iostream> using namespace st

POJ3041Asteroids(最小点覆盖+然而并不是很理解why)

Asteroids Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 18289   Accepted: 9968 Description Bessie wants to navigate her spaceship through a dangerous asteroid field in the shape of an N x N grid (1 <= N <= 500). The grid contains K as

二分图匹配 + 最小点覆盖 - Vertex Cover

Vertex Cover Problem's Link Mean: 给你一个无向图,让你给图中的结点染色,使得:每条边的两个顶点至少有一个顶点被染色.求最少的染色顶点数. analyse: 裸的最小点覆盖问题,二分图的最大匹配,直接套模版即可. Time complexity: O(N^2) view code

hdu 1151 或 poj 1422 二分图 最小点覆盖集

最小点覆盖集的裸题,只要“拆点建边”然后求出最大匹配,则:最小点覆盖集的大小 = 点数 - 最大匹配 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 6 const int N = 121; 7 const int M = 5000; 8 bool visit[N]; 9 int mark[N]; 10 int head[N]; 11 int

POJ3041 Asteroids【二分图最小点覆盖】

题目链接: http://poj.org/problem?id=3041 题目大意: 有一个N*N的矩阵,有些格子上有障碍物(坐标为(x,y) ),在消除这些障碍物的时候,可以一次性消除 该障碍物同一行所有的障碍物,或是一次性消除该障碍物同一列所有的障碍物.只能选择清理该行或是 清理该列.问:最小进行多少次消除,就可以清理所有的障碍物. 思路: 可以将每一行当做一个点,这样总共有N个点,作为二分图的一边.将每一列当做一个点,这样又有N 个点,作为二分图的另一边.将有障碍物的行点和列点连接起来,每

二分图的最小点覆盖和最大独立集

一.二分图的最小点覆盖 无向图的最小点覆盖,就是选取图中最少的点使得每条边至少有一个端点被选中. 而二分图的最小点覆盖 = 最大匹配. 二.二分图的最大独立集 无向图的最大独立集,就是从无向图中选取尽量多的点,这些点两两不邻接. 而二分图的最大独立集 = 点总数 - 最大匹配. 解析见链接:http://hihocoder.com/problemset/problem/1127

hihoCoder #1127 : 二分图二&#183;二分图最小点覆盖和最大独立集

#1127 : 二分图二·二分图最小点覆盖和最大独立集 Time Limit:10000ms Case Time Limit:1000ms Memory Limit:256MB 描述 在上次安排完相亲之后又过了挺长时间,大家好像都差不多见过面了.不过相亲这个事不是说那么容易的,所以Nettle的姑姑打算收集一下之前的情况并再安排一次相亲.所以现在摆在Nettle面前的有2个问题: 1.姑姑想要了解之前所有相亲的情况.对于任一个一次相亲,只要跟参与相亲的两人交流就可以得到这次相亲的情况.如果一个人