最小圓覆蓋(隨機增量法&模擬退火法)


http://acm.hdu.edu.cn/showproblem.php?pid=3007

相關題型連接:

http://acm.hdu.edu.cn/showproblem.php?pid=3932

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=450

Buried memory

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2368    Accepted Submission(s): 1291

Problem Description Each person had do something foolish along with his or her growth.But,when he or she did this that time,they could not predict that this thing is a mistake and they will want this thing would rather not happened.
The world king Sconbin is not the exception.One day,Sconbin was sleeping,then swakened by one nightmare.It turned out that his love letters to Dufein were made public in his dream.These foolish letters might ruin his throne.Sconbin decided to destroy the letters by the military exercises's opportunity.The missile is the best weapon.Considered the execution of the missile,Sconbin chose to use one missile with the minimum destruction.
Sconbin had writen N letters to Dufein, she buried these letters on different places.Sconbin got the places by difficult,he wants to know where is the best place launch the missile,and the smallest radius of the burst area. Let's help Sconbin to get the award.
 
Input There are many test cases.Each case consists of a positive integer N(N<500,^V^,our great king might be a considerate lover) on a line followed by N lines giving the coordinates of N letters.Each coordinates have two numbers,x coordinate and y coordinate.N=0 is the end of the input file.  
Output For each case,there should be a single line in the output,containing three numbers,the first and second are x and y coordinates of the missile to launch,the third is the smallest radius the missile need to destroy all N letters.All output numbers are rounded to the second digit after the decimal point.
 
Sample Input
3
1.00 1.00
2.00 2.00
3.00 3.00
0
 
Sample Output
2.00 2.00 1.41

方法一:隨機增量法:

分析:用最小的圓覆蓋住所有的點:隨機增量法復雜度是O(n);

2、算法及原理算法介紹:我們本次算法的設計是基於這樣一個簡單直觀的性質:

在既定的給定點條件下,如果引入一張新的半平面,只要此前的最優解頂點(即唯一確定最小包圍圓的幾個關鍵頂點)能夠包含於其中,則不必對此最優解進行修改,亦即此亦為新點集的最優解;否則,新的最優解頂點必然位於這個新的半空間的邊界上。定理可以通過反證法證明。於是,基於此性質,我們便可得到一個類似於線性規划算法的隨機增量式算法。定義Di為相對於pi的最小包圍圓。此算法實現的關鍵在於對於pi∉Di-1時的處理。顯然,如果pi∈Di-1,則Di= Di-1;否則,需要對Di另外更新。而且,Di的組成必然包含了pi;因此,此種情況下的最小包圍圓是過pi點且覆蓋點集{ p1 ,p2 ,p3 ……pi-1}的最小包圍圓。則仿照上述處理的思路,Di={ p1 ,pi },逐個判斷點集{ p2 ,p3 ……pi-1 },如果存在pj∉ Di,則Di={pj,pi }。同時,再依次對點集{ p1 ,p2 ,p3 ……pj-1 }判斷是否滿足pk∈Di,若有不滿足,則Di={pk ,pj,pi }。由於,三點唯一地確定一個圓,故而,只需在此基礎上判斷其他的點是否位於此包圍圓內,不停地更新pk。當最內層循環完成時,退出循環,轉而更新pj;當次內層循環結束時,退出循環,更新pi。當i=n時,表明對所有的頂點均已處理過 ,此時的Dn即表示覆蓋了給定n個點的最小包圍圓。

總結:

假設圓O是前i-1個點得最小覆蓋圓,加入第i個點,如果在圓內或邊上則什么也不做。否,新得到的最小覆蓋圓肯定經過第i個點。然后以第i個點為基礎(半徑為0),重復以上過程依次加入第j個點,若第j個點在圓外,則最小覆蓋圓必經過第j個點。重復以上步驟(因為最多需要三個點來確定這個最小覆蓋圓,所以重復三次)。遍歷完所有點之后,所得到的圓就是覆蓋所有點得最小圓。證明可以考慮這么做:最小圓必定是可以通過不斷放大半徑,直到所有以任意點為圓心,半徑為半徑的圓存在交點,此時的半徑就是最小圓。所以上述定理可以通過這個思想得到。這個做法復雜度是O(n)的,當加入圓的順序隨機時,因為三點定一圓,所以不在圓內概率是3/i,求出期望可得是O(n)。

方法二:模擬退火法:對於每個枚舉的點找到改點到所給點的最遠點的距離,然后保證這個距離最小,即為所求圓的半徑;

程序:

方法一:隨機增量法:

#include"string.h"
#include"stdio.h"
#include"queue"
#include"stack"
#include"vector"
#include"algorithm"
#include"iostream"
#include"math.h"
#include"stdlib.h"
#define M 522
#define inf 100000000
#define eps 1e-8
#define PI acos(-1.0)
using namespace std;
double X,Y;
struct Point
{
double x,y;
}p[M];
struct Triangle
{
Point v[3];
};
struct Circle
{
Point center;
double r;
};
double pow(double x)
{
return x*x;
}
double Len(Point a,Point b)
{
return sqrt(pow(a.x-b.x)+pow(a.y-b.y));
}
double TriangleArea(Triangle a)//求三角形的面積
{
double px1=a.v[1].x-a.v[0].x;
double py1=a.v[1].y-a.v[0].y;
double px2=a.v[2].x-a.v[0].x;
double py2=a.v[2].y-a.v[0].y;
return fabs(px1*py2-px2*py1)/2;
}
Circle CircleOfTriangle(Triangle t)//就三角形外接圓
{
Circle tmp;
double a=Len(t.v[0],t.v[1]);
double b=Len(t.v[0],t.v[2]);
double c=Len(t.v[1],t.v[2]);
tmp.r=a*b*c/4/TriangleArea(t);
double a1=t.v[1].x-t.v[0].x;
double b1=t.v[1].y-t.v[0].y;
double c1=(a1*a1+b1*b1)/2;
double a2=t.v[2].x-t.v[0].x;
double b2=t.v[2].y-t.v[0].y;
double c2=(a2*a2+b2*b2)/2;
double d=a1*b2-a2*b1;
tmp.center.x=t.v[0].x+(c1*b2-c2*b1)/d;
tmp.center.y=t.v[0].y+(a1*c2-a2*c1)/d;
return tmp;
}
void Run(int n)
{
random_shuffle(p+1,p+n+1);//隨機排序取點
int i,j,k;
Circle tep;
tep.center=p[1];
tep.r=0;
for(i=2;i<=n;i++)
{
if(Len(p[i],tep.center)>tep.r+eps)
{
tep.center=p[i];
tep.r=0;
for(j=1;j<i;j++)
{
if(Len(p[j],tep.center)>tep.r+eps)
{
tep.center.x=(p[i].x+p[j].x)/2;
tep.center.y=(p[i].y+p[j].y)/2;
tep.r=Len(p[i],p[j])/2;
for(k=1;k<j;k++)
{
if(Len(p[k],tep.center)>tep.r+eps)
{
Triangle t;
t.v[0]=p[i];
t.v[1]=p[j];
t.v[2]=p[k];
tep=CircleOfTriangle(t);
}
}
}
}
}
}
printf("%.2lf %.2lf %.2lf\n",tep.center.x,tep.center.y,tep.r);
}
int main()
{
int n,i;
while(scanf("%d",&n),n)
{
for(i=1;i<=n;i++)
scanf("%lf%lf",&p[i].x,&p[i].y);
Run(n);
}
}

方法二:模擬退火法:(hdu3932)

#include"string.h"
#include"stdio.h"
#include"queue"
#include"stack"
#include"vector"
#include"algorithm"
#include"iostream"
#include"math.h"
#include"stdlib.h"
#define M 1009
#define inf 100000000
#define eps 1e-8
#define PI acos(-1.0)
using namespace std;
double X,Y;
int n;
struct Point
{
double x,y,dis;
Point(){}
Point(double xx,double yy){x=xx;y=yy;}
bool check(){
if(x>0&&y>0&&x<X&&y<Y)return true;
return false;
}
}p[M],q[50];
double pow(double x)
{
return x*x;
}
double Len(Point a,Point b)
{
return sqrt(pow(a.x-b.x)+pow(a.y-b.y));
}
double fun(Point a)
{
double maxi=0;
for(int i=1;i<=n;i++)
{
double L=Len(a,p[i]);
if(maxi<L)
maxi=L;
}
return maxi;
}
int main()
{
int i;
while(scanf("%lf%lf%d",&X,&Y,&n)!=EOF)
{
for(i=1;i<=n;i++)
scanf("%lf%lf",&p[i].x,&p[i].y);
int po=15,est=15;
for(int i=1;i<=po;i++)
{
q[i].x=(rand()%1000+1)/1000.0*X;
q[i].y=(rand()%1000+1)/1000.0*Y;
q[i].dis=fun(q[i]);
}
double temp=max(X,Y);
while(temp>0.001)
{
for(int i=1;i<=po;i++)
{
for(int j=1;j<=est;j++)
{
double rad=(rand()%1000+1)/1000.0*PI*2;
Point cur;
cur.x=q[i].x+temp*cos(rad);
cur.y=q[i].y+temp*sin(rad);
if(!cur.check())continue;
cur.dis=fun(cur);
if(cur.dis<q[i].dis)
q[i]=cur;
}
}
temp*=0.8;
}
int id=1;
for(int i=1;i<=po;i++)
if(q[id].dis>q[i].dis)
id=i;
printf("(%.1lf,%.1lf).\n%.1lf\n",q[id].x,q[id].y,q[id].dis);
}
return 0;
}




注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com