Bubble Cup 8 finals E. Spectator Riots (575E)

题意:

一个长宽是100000单位的球场上有很多暴动的观众,每个观众都有一个速度v,

在一秒内,观众会等概率地移动到与原位置的曼哈顿距离<=v的地方(不会移动到界外)。

你需要选取三个位置,这三个位置要求满足在一秒之后可能会出现观众。

(这里不需要考虑概率大小,只要概率不为0就是满足的)

然后过这三点作圆,请选取在初始状态一秒后圆内观众数的期望值最大的方案输出。

如果有多种,输出半径最大的方案。

 

题解:

第一眼看起来非常可怕…

什么每秒移动速度呀…什么期望呀…先被吓死就做不了了…

其实是假装要扯上概率…

稍微想想就可以发现,总会有一种方案把全部可能位置覆盖…

考虑所有可能位置的点集的凸包,把凸包上的点逐个加入图中并维护一个圆,

假如现在圆上已经存在三个点,正要加入下一个点,

那么如果下一个点在圆内,则不用作任何改动就能保证圆包含所有点,

如果下一个点在圆外,则那个点一定在新的圆上,

那么考虑原来的三个点中让两个不动,那么这两点连线的垂直平分线不动。

那么因为新的圆半径要增大,所以这两个不动的点与圆心的距离(就是半径)会变大,

所以导致圆心在这条垂直平分线上移动时朝着远离这两个点的方向移动…

这时考虑不动的两点中的一个和原来的任意一个点以及圆心构成的三角形,

把这个三角形的边和新旧圆心连起来就可以看出三角形的一角增大一角减小,

(动手画一画可以画出一个蝴蝶出来)

可以证明这个三角形中在新圆上的角比不在新圆上的角要小。

(因为这两个角在旧圆中就已经满足小于等于的关系了,现在小的减小大的增大,显然还是满足)

那么根据大角对大边,这个三角形中不在新圆上的角的顶点离圆心的距离小于新圆的半径,

即顶点在圆内。

所以按照这种方法可以保证最后所有点都在圆内。

有了这种保证,期望什么的就不用管了,答案一定是包含所有点的方案…

然后我们需要找到那个包含全部点并且半径最大的方案。

理所当然地可以有一个猜想:答案一定凸包上相邻的三个点,

感觉上是这样的,因为这样圆弧曲率最小,半径最大…

但是我们要证明它。

考虑分两步证明,首先证明可行性,然后证明最优性。

可行性在上面已经证明了,把相邻三个点放进图中,然后逐个把凸包中的点放进去是可行的。

然后是最优性。假设对于所有的最优方案,不满足那三点相邻,

那么根据假设,在某两点之中,一定存在一个点,并且这个点与这两点确定的圆要比当前小。

分析这个点的位置,如果它在当前圆内,那么这个点与旁边两点确定的圆会比当前圆大。

(因为和当前三点相比,其中两点相同,所以一条垂直平分线相同)

(而在当前圆内那一点与两点中一点的连线的垂直平分线与不变的垂直平分线的交点会变远)

(这一点可以用角度大小关系说明)

因为这个点与旁边两点确定的圆会比当前圆大,与假设不符,所以舍去这种情况。

如果它在当前圆外,与当前圆是最优解矛盾(因为有点在圆外就不是可行解),所以也舍去。

如果它在当前圆上,那么这个点和旁边的两点可以组成一个三点相邻的最优方案,也与假设矛盾。

所以假设不成立…所以它的否命题“存在一个最优方案,满足三点相邻”成立。

于是我们有了这题的做法:在凸包上相邻三个点中找出所有可行解,并在里面取最优。

然后问题又来了,我们怎么知道那些是可行解呢?

我们可以证明,半径最大的方案(不一定是三点相邻)一定是最优解。

因为从我们最开始的过程可以看出,把不可行方案变成可行解时半径会增大。

所以如果一个方案的半径已经最大,无法再增大,那么一定是可行解。

同时又因为半径最大,所以是最优解。

反过来,最优解一定是半径最大的方案,否则不满足最优性。

有了这个结论后,我们就可以确定相邻三点确定的圆中的最大的那个就是我们要找的最优解。

因为所有相邻三点中存在一个最优方案,而这个方案同时是半径最大的方案,

所以在相邻三点中找到的半径最大的方案就是一个全局的最优方案。

 

一句话总结做法就是:求凸包,在相邻三点的方案中找出半径最大的就是答案。

(另外半径的求法可以用正弦定理推,最后结论是r=abc/4S,abc是内接圆边长)

 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define sqr(x) ((x)*(x))
#define dist(a,b) (sqrt(sqr(a.x-b.x)+sqr(a.y-b.y)))
using namespace std;
inline int read()
{
	int s = 0; char c; while((c=getchar())<'0'||c>'9');
	do{s=s*10+c-'0';}while((c=getchar())>='0'&&c<='9');
	return s;
}
typedef long long lint;
const int N = 100010, RN = 1e5;
int n,tot,mi,t;
int cv[N*6];
struct vct
{
	lint x,y; double ang;
	vct(){}
	vct(int x,int y):x(x),y(y){};
	bool operator == (const vct &b)const{ return x==b.x&&y==b.y; }
}v[N*6];
inline lint cross(lint ax,lint ay,lint bx,lint by){ return ax*by-ay*bx; }
void insertvct(int x,int y)
{
	int i = ++tot; v[i].x = x, v[i].y = y;
	if(v[i].x<v[mi].x||(v[i].x==v[mi].x&&v[i].y<v[mi].y)) mi = i;
}
bool cmp(const vct &a,const vct &b){ if(a.ang!=b.ang) return a.ang<b.ang; return a.x>b.x; }
void make_convex()
{
	cv[1] = 1; int k = 2; 
	while(v[k]==v[1]) k++; cv[2] = k++;
	while(v[k]==v[cv[2]]) k++; cv[t=3] = k;
	v[++tot] = v[1];
	for(int i=k+1;i<=tot;i++)
	{
		while(t>=3&&cross(v[i].x-v[cv[t]].x,v[i].y-v[cv[t]].y,
				  v[cv[t]].x-v[cv[t-1]].x,v[cv[t]].y-v[cv[t-1]].y)>=0) t--;
		cv[++t] = i;
	}
	t--;
}
inline double getr(const vct &a,const vct &b,const vct &c)
{
	double aa = dist(a,b), bb = dist(b,c), cc = dist(c,a);
	double ss = 2.0*abs(cross(b.x-a.x,b.y-a.y,c.x-a.x,c.y-a.y));
	if(ss<=1e-10) return 0;
	return aa*bb*cc/ss;
}
int main()
{
	int i,j,aa,bb,cc;
	n = read(), mi = 1;
	for(i=1;i<=n;i++)
	{
		aa = read(), bb = read(); cc = read();
		if(aa-cc>=0) insertvct(aa-cc,bb);
		else insertvct(0,min(RN,bb+cc-aa)), insertvct(0,max(0,bb-cc+aa));
		if(aa+cc<=RN) insertvct(aa+cc,bb);
		else insertvct(RN,min(RN,bb+cc-(RN-aa))), insertvct(RN,max(0,bb-cc+(RN-aa)));
		if(bb-cc>=0) insertvct(aa,bb-cc);
		else insertvct(min(RN,aa+cc-bb),0), insertvct(max(0,aa-cc+bb),0);
		if(bb+cc<=RN) insertvct(aa,bb+cc);
		else insertvct(min(RN,aa+cc-(RN-bb)),RN), insertvct(max(0,aa-cc+(RN-bb)),RN);
	}
	swap(v[1],v[mi]);
	for(i=2;i<=tot;i++) v[i].ang = atan2(v[i].y-v[1].y,v[i].x-v[1].x);
	sort(v+2,v+1+tot,cmp);
	make_convex();
	double mx = getr(v[cv[t]],v[cv[1]],v[cv[2]]), tmp; int a1 = t, a2 = 1, a3 = 2;
	if((tmp=getr(v[cv[t-1]],v[cv[t]],v[cv[1]]))>mx) a1 = t-1, a2 = t, a3 = 1, mx = tmp;
	for(i=3;i<=t;i++)
		if((tmp=getr(v[cv[i-2]],v[cv[i-1]],v[cv[i]]))>mx) 
			a3 = i, mx = tmp;
	if(a3>=3) a1 = a3-2, a2 = a3-1;
	printf("%I64d %I64d\n%I64d %I64d\n%I64d %I64d\n",
	       v[cv[a1]].x,v[cv[a1]].y,v[cv[a2]].x,v[cv[a2]].y,v[cv[a3]].x,v[cv[a3]].y);
	return 0;
}

 

posted @ 2015-12-03 20:11  MoebiusMeow  阅读(514)  评论(0编辑  收藏  举报