首页 > ACM题库 > HDU-杭电 > HDU 3995-Perfect Faceless Void-计算几何-[解题报告]HOJ
2015
04-14

HDU 3995-Perfect Faceless Void-计算几何-[解题报告]HOJ

Perfect Faceless Void

问题描述 :

DotA is a popular game now. There is a hero called Faceless Void (Darkterror,FV). The hero has a powerful skill called “Chronosphere”. This skill is described as follows: FV can create a Time Enchantment that neither the enemy units nor the friend units in it can move except FV himself. We can treat the Time Enchantment as a circle. Any unit which is in the circle or just on the edge of the circle can’t move.

Now a new Crazy (Imba) version of the game has been issued. In the new version, FV can control the size of the Time Enchantment (the radius of the circle). More bigger the circle is, more mana(magic value, blue) FV costs. What’s more, there is a new set about the unit which is just on the edge of the circle: if the unit is an enemy, it must remain stationary. Otherwise, the unit is free of the skill. Certainly, a unit in the circle must remain stationary whether it is an enemy or a friend.

Mission Impossible

Then come the problem, there are n (1 <= n <= 10000) enemy units and m (1 <= m <= 10000) friend units in the two dimensional plane, every unit can be treated as a point which is described by a coordinate (x,y). As a perfect player, FV must make sure that all the n enemy units are affected by the skill and all the m friend units are free of it. In additional, FV should choose a solution that cost least mana. How to set the center of the Time Enchantment and the radius of it? It is ensured that there always exists a solution.

输入:

There are several test cases (about 50). The first line consists of two integers n and m (1<= n, m <= 10000) indicate the number of enemy units and the number of friend units. Then there are n+m lines, first n lines describe the coordinates of the n enemy units, and the last m lines describe the coordinates of the m friend units. Every line contains two real numbers.

输出:

There are several test cases (about 50). The first line consists of two integers n and m (1<= n, m <= 10000) indicate the number of enemy units and the number of friend units. Then there are n+m lines, first n lines describe the coordinates of the n enemy units, and the last m lines describe the coordinates of the m friend units. Every line contains two real numbers.

样例输入:

2 1
0.0 0.0
2.0 0.0
1.0 2.0

2 1
0.0 0.0 
2.0 0.0
1.0 1.0

2 2
0.0 0.0
4.0 0.0
2.0 1.0
2.0 2.0

样例输出:

1.000 0.000
1.000
1.000 0.000
1.000
2.000 -1.500
2.500

这题出2了,下次注意点。

时间卡紧了导致一些不太好的最小包围圆模板过不了。

精度上要求有点高,可能导致了一些wa。

有的队方法完全正确,由于出题的经验不足,可惜了。

直接把标程贴出来吧。

题意:两个点集的最小包围圆,  随机增量的时候,改一下模板就行了。

/*
*最小包围圆随机增量O(n)变形
* by tju_accry
*
*本机测试时间:
*real	0m0.957s
*user	0m0.944s
*sys	0m0.012s

*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

#define sqr(a) ((a)*(a))
#define trarea(p) fabs ((vdet(p[0],p[1],p[2])/2.0))
double const EPS = 1e-12;
int const maxn = 20011;
struct point{double x,y;int flag;};
struct circle{
		point c;
		double r;
};
inline double vdet(point op,point p1,point p2){
		return (p1.x-op.x)*(p2.y-op.y)-(p2.x-op.x)*(p1.y-op.y);
}
inline double dis(point a,point b){
		return sqr(a.x-b.x)+sqr(a.y-b.y);
}
inline point get_out_circle(point p[]){  //三角形外接圆圆心
		double c1,c2,xa,xb,xc,ya,yb,yc;
		point o;
		xa=p[0].x,xb=p[1].x,xc=p[2].x;
		ya = p[0].y,yb = p[1].y,yc = p[2].y;
		c1 = (sqr(xa) + sqr(ya) - sqr(xb) - sqr(yb))/2.0;
		c2 = (sqr(xa) + sqr(ya) - sqr(xc) - sqr(yc))/2.0;
		o.x = (c1*(ya-yc)-c2*(ya-yb))/((xa-xb)*(ya-yc)-(xa-xc)*(ya-yb));
		o.y = (c1*(xa-xc)-c2*(xa-xb))/((ya-yb)*(xa-xc)-(ya-yc)*(xa-xb));
		return o;
}
inline double get_out_r(point p[]){  //三角形外接圆半径
		double a = dis(p[0],p[1]),b = dis(p[1],p[2]),c = dis(p[2],p[0]),s = trarea(p);
		return a*b*c/sqr(4*s);
}
point must_on[3],p[maxn];
circle mc;
inline void get_circle(int tm){  //一点,两点圆,三点圆
		switch(tm){
				case 0:mc.r = -1;
					   break;
				case 1:mc.r = 0,mc.c = must_on[0];
					   break;
				case 2:{
							   mc.r = dis(must_on[0],must_on[1])/4.0;
							   mc.c.x = (must_on[0].x+must_on[1].x)/2.0;
							   mc.c.y = (must_on[0].y + must_on[1].y)/2.0;
					   }break;
				case 3:{
							   mc.r = get_out_r(must_on);
							   mc.c = get_out_circle(must_on);
					   }break;
		}
}
inline void min_circle(int t,int ton){
		get_circle(ton);
		if(ton >= 3)return;
		for(int i = 0; i < t; ++i){
				/*
				//求一个点集的最小包围圆
				if(dis(mc.c,p[i]) > mc.r + EPS){
					must_on[ton] = p[i];
					min_circle(i,ton+1);
				}
				*/

				/*本题*/
				if(p[i].flag == 1){
					if(dis(mc.c,p[i]) > mc.r + EPS){  //A集合点在圆内或圆周上
						must_on[ton] = p[i];
						min_circle(i,ton+1);
					}
				}
				else {
					if(dis(mc.c,p[i]) + EPS < mc.r){  //B集合的点不在圆内(可以在圆周上)
						must_on[ton] = p[i];
						min_circle(i,ton+1);
					}
				}

		}
}
int main(){
		int n,m;
		//freopen("data.in","r",stdin);
		//freopen("data.out","w",stdout);
		while (scanf("%d%d",&n,&m) != EOF){
				for(int i = 0; i < n; ++i){
						scanf("%lf%lf",&p[i].x,&p[i].y);
						p[i].flag = 1;
				}

				for(int i = n; i < m + n; ++i){
						scanf("%lf%lf",&p[i].x,&p[i].y);
						p[i].flag = 2;
				}
				n = n + m;
				random_shuffle(p,p+n); //随机化序列元素
				min_circle(n,0);
				printf("%.3lf %.3lf\n%.3lf\n",mc.c.x,mc.c.y,sqrt(mc.r));
		}
		return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

参考:http://blog.csdn.net/accry/article/details/6744233


  1. 换句话说,A[k/2-1]不可能大于两数组合并之后的第k小值,所以我们可以将其抛弃。
    应该是,不可能小于合并后的第K小值吧