和吴昊一起玩推理 Round 8 —— 计算几何一系列(C)—— 圆上知道一点求另外两点组成一个周长最长的三角形(HDOJ 1700)
Source: HDOJ 1700
【数学证明】
设R是圆半径,A,B,C是三角形的角,由正弦定理得a/sinA =b/sinB=c/sinC=2R
故a+b+c=2R(sinA+sinB+sinC),当R确定求周长a+b+c最大,归结为求sinA+sinB+sinC的最大.
设Y=sinA+sinB+sinC,先固定角A,
Y=sinA+sinB+sinC=sinA+2sin((B+C)/2)cos((B-C)/2)
=sinA+2cos(A/2)cos((B-C)/2)
因为A是定值,故只有B=C时,Y才有最大值,同理分别再固定角B,C,则当C=A,A=B时,
Y才有最大值,故A=B=C=60时,Y值最大,即周长a+b+c最大.
也即同圆或等圆中周长最大的三角形是等边三角形.
1 【一般方法】
2
3
4
5 #include<stdio.h>
6 #include<math.h>
7 #define pi acos(-1.0)
8 #define epx 0.0005
9 int main()
10 {
11 int t;
12 double x1,y1,x2,y2,x3,y3,a,r,b;
13 scanf("%d",&t);
14 while(t--&&scanf("%lf%lf",&x1,&y1))
15 {
16 r=sqrt(x1*x1+y1*y1);
17 if(x1!=0&&y1!=0)
18 {
19 if(x1<0&&y1<0)a=pi+atan(y1/x1);
20 else if(x1<0&&y1>0)a=pi+atan(y1/x1);
21 else a=atan(y1/x1);
22 }
23 else if(x1==0&&y1!=0)
24 {
25 if(y1>0)a=pi/2;
26 else a=-pi/2;
27 }
28 else if(x1!=0&&y1==0)
29 {
30 if(x1>0)a=0;
31 else a=pi;
32 }
33 b=2*pi/3+a;
34 x2=cos(b)*r;y2=sin(b)*r;
35 x3=-(x1+x2);y3=-(y1+y2);
36 if(fabs(y2-y3)<epx)
37 {
38 if(x2<x3)printf("%.3lf %.3lf %.3lf %.3lf\n",x2,y2,x3,y3);
39 else printf("%.3lf %.3lf %.3lf %.3lf\n",x3,y3,x2,y2);
40 }
41 else
42 {
43 if(y2<y3)printf("%.3lf %.3lf %.3lf %.3lf\n",x2,y2,x3,y3);
44 else printf("%.3lf %.3lf %.3lf %.3lf\n",x3,y3,x2,y2);
45 }
46 }
47 }
48
49
50 【复平面方法】
51
52 #include<stdio.h>
53 #include<math.h>
54 #define s sqrt(3.0)
55 #define epx 0.0005
56 int main()
57 {
58 int t;
59 double x1,y1,x2,y2,x3,y3,a,r,b;
60 scanf("%d",&t);
61 while(t--&&scanf("%lf%lf",&x1,&y1))
62 {
63 x2=-(x1+s*y1)/2;
64 y2=(s*x1-y1)/2;
65 x3=-(x1+x2);y3=-(y1+y2);
66 if(fabs(y2-y3)<epx)
67 {
68 if(x2<x3)printf("%.3lf %.3lf %.3lf %.3lf\n",x2,y2,x3,y3);
69 else printf("%.3lf %.3lf %.3lf %.3lf\n",x3,y3,x2,y2);
70 }
71 else
72 {
73 if(y2<y3)printf("%.3lf %.3lf %.3lf %.3lf\n",x2,y2,x3,y3);
74 else printf("%.3lf %.3lf %.3lf %.3lf\n",x3,y3,x2,y2);
75 }
76 }
77 }
78
79 【向量法】
80
81 设 P(x,y),一个方程是pow(x,2)+pow(y,2)=pow(r,2);另一个方程是根据向量知识,向量的夹角公式得到方程。因为圆心角夹角 为120度,已知一个向量(即一个点作标),所以COS(2PI/3)=a*b/|a|*|b|;(a,b为向量);已知角和a向量,就可求b向量 b(x,y).由方程组可求得(x,y);最后得到的是一元二次方程组,可得到两个解,即为两个点的作标。
82
83 #include<stdio.h>
84 #include<math.h>
85 struct Point
86 {
87 double x;
88 double y;
89 };
90 int main()
91 {
92 Point p1,p2,p3;
93 double a,b,c,r,delta;
94 int t,i;
95 for (;scanf("%d",&t)!=EOF;)
96 {
97 for (i=0;i<t;i++)
98 {
99 scanf("%lf%lf",&p1.x,&p1.y);
100 r=sqrt(p1.x*p1.x+p1.y*p1.y);
101 a=p1.x*p1.x+p1.y*p1.y;
102 b=p1.y*r*r;
103 c=(-p1.x*p1.x*r*r+r*r*r*r/4);
104 delta=b*b-4*a*c;
105 p2.y=(-1*b-sqrt(delta))/(2*a);
106 p3.y=(-1*b+sqrt(delta))/(2*a);
107 if(p1.x==0)
108 {
109 p2.x=-sqrt(r*r-p2.y*p2.y);
110 p3.x=sqrt(r*r-p2.y*p2.y);
111 }
112 else
113 {
114 p2.x=(-1*r*r/2-p1.y*p2.y)/p1.x;
115 p3.x=(-1*r*r/2-p1.y*p3.y)/p1.x;
116 }
117
118 printf("%.3lf %.3lf %.3lf %.3lf\n",p2.x,p2.y,p3.x,p3.y);
119 }
120 }
121 return 0;
122 }
123 【方程组法】
124
125 已知一个以(0,0)为圆心的圆和圆上的一点(x0,y0)求圆上的另外两点(x1,y1,)(x2,y2),使得向量(x1,y1)(x2,y2)和(x0,y0)各个向量两两之间夹角为120度
126
127 此题主要用到向量的叉乘和点乘列出两个二元一次方程组
128
129 1.
130
131 (x0,y0)X (x1,y1) = sin(120)*R^2 (r为圆的半径)
132
133 (x0,y0) * (x1,y1) = cos(120)*R^2
134
135 结果为:
136
137 x1=b*x0-a*y0; a=sin120
138 y1=b*y0+a*x0; b=cos120;
139
140 2.
141
142 (x0,y0)X (x2,y2) = -sin(120)*R^2 (r为圆的半径)
143
144 (x0,y0) * (x2,y2) = cos(120)*R^2
145
146 注:题目假设向量(x1,y1)在向量(x0,y0)逆时针方向 故叉乘结果为正值
147
148 (x2,y2)于(x0,y0)的顺时针方向 故叉乘结果为负值
149
150 #include <stdlib.h>
151 #include <stdio.h>
152 #include <math.h>
153 int main(int argc, char** argv) {
154
155
156 double a,b,sinx,cosx,x0,y0,x1,y1,x2,y2;
157 int t;
158
159 a=sinx=sqrt(3.0)/2;
160 b=cosx=-0.5;
161 scanf("%d",&t);
162 while(t--)
163 {
164 scanf("%lf%lf",&x0,&y0);
165
166 x1=b*x0-a*y0;
167 y1=b*y0+a*x0;
168 x2=b*x0+a*y0;
169 y2=b*y0-a*x0;
170 if(y1<y2||((abs(y1-y2)<0.005)&&x1<x2))
171 {
172 printf("%.3lf %.3lf %.3lf %.3lf\n",x1,y1,x2,y2);
173 }
174 else
175 printf("%.3lf %.3lf %.3lf %.3lf\n",x2,y2,x1,y1);
176
177 }
178
179 return (EXIT_SUCCESS);
180 }
2
3
4
5 #include<stdio.h>
6 #include<math.h>
7 #define pi acos(-1.0)
8 #define epx 0.0005
9 int main()
10 {
11 int t;
12 double x1,y1,x2,y2,x3,y3,a,r,b;
13 scanf("%d",&t);
14 while(t--&&scanf("%lf%lf",&x1,&y1))
15 {
16 r=sqrt(x1*x1+y1*y1);
17 if(x1!=0&&y1!=0)
18 {
19 if(x1<0&&y1<0)a=pi+atan(y1/x1);
20 else if(x1<0&&y1>0)a=pi+atan(y1/x1);
21 else a=atan(y1/x1);
22 }
23 else if(x1==0&&y1!=0)
24 {
25 if(y1>0)a=pi/2;
26 else a=-pi/2;
27 }
28 else if(x1!=0&&y1==0)
29 {
30 if(x1>0)a=0;
31 else a=pi;
32 }
33 b=2*pi/3+a;
34 x2=cos(b)*r;y2=sin(b)*r;
35 x3=-(x1+x2);y3=-(y1+y2);
36 if(fabs(y2-y3)<epx)
37 {
38 if(x2<x3)printf("%.3lf %.3lf %.3lf %.3lf\n",x2,y2,x3,y3);
39 else printf("%.3lf %.3lf %.3lf %.3lf\n",x3,y3,x2,y2);
40 }
41 else
42 {
43 if(y2<y3)printf("%.3lf %.3lf %.3lf %.3lf\n",x2,y2,x3,y3);
44 else printf("%.3lf %.3lf %.3lf %.3lf\n",x3,y3,x2,y2);
45 }
46 }
47 }
48
49
50 【复平面方法】
51
52 #include<stdio.h>
53 #include<math.h>
54 #define s sqrt(3.0)
55 #define epx 0.0005
56 int main()
57 {
58 int t;
59 double x1,y1,x2,y2,x3,y3,a,r,b;
60 scanf("%d",&t);
61 while(t--&&scanf("%lf%lf",&x1,&y1))
62 {
63 x2=-(x1+s*y1)/2;
64 y2=(s*x1-y1)/2;
65 x3=-(x1+x2);y3=-(y1+y2);
66 if(fabs(y2-y3)<epx)
67 {
68 if(x2<x3)printf("%.3lf %.3lf %.3lf %.3lf\n",x2,y2,x3,y3);
69 else printf("%.3lf %.3lf %.3lf %.3lf\n",x3,y3,x2,y2);
70 }
71 else
72 {
73 if(y2<y3)printf("%.3lf %.3lf %.3lf %.3lf\n",x2,y2,x3,y3);
74 else printf("%.3lf %.3lf %.3lf %.3lf\n",x3,y3,x2,y2);
75 }
76 }
77 }
78
79 【向量法】
80
81 设 P(x,y),一个方程是pow(x,2)+pow(y,2)=pow(r,2);另一个方程是根据向量知识,向量的夹角公式得到方程。因为圆心角夹角 为120度,已知一个向量(即一个点作标),所以COS(2PI/3)=a*b/|a|*|b|;(a,b为向量);已知角和a向量,就可求b向量 b(x,y).由方程组可求得(x,y);最后得到的是一元二次方程组,可得到两个解,即为两个点的作标。
82
83 #include<stdio.h>
84 #include<math.h>
85 struct Point
86 {
87 double x;
88 double y;
89 };
90 int main()
91 {
92 Point p1,p2,p3;
93 double a,b,c,r,delta;
94 int t,i;
95 for (;scanf("%d",&t)!=EOF;)
96 {
97 for (i=0;i<t;i++)
98 {
99 scanf("%lf%lf",&p1.x,&p1.y);
100 r=sqrt(p1.x*p1.x+p1.y*p1.y);
101 a=p1.x*p1.x+p1.y*p1.y;
102 b=p1.y*r*r;
103 c=(-p1.x*p1.x*r*r+r*r*r*r/4);
104 delta=b*b-4*a*c;
105 p2.y=(-1*b-sqrt(delta))/(2*a);
106 p3.y=(-1*b+sqrt(delta))/(2*a);
107 if(p1.x==0)
108 {
109 p2.x=-sqrt(r*r-p2.y*p2.y);
110 p3.x=sqrt(r*r-p2.y*p2.y);
111 }
112 else
113 {
114 p2.x=(-1*r*r/2-p1.y*p2.y)/p1.x;
115 p3.x=(-1*r*r/2-p1.y*p3.y)/p1.x;
116 }
117
118 printf("%.3lf %.3lf %.3lf %.3lf\n",p2.x,p2.y,p3.x,p3.y);
119 }
120 }
121 return 0;
122 }
123 【方程组法】
124
125 已知一个以(0,0)为圆心的圆和圆上的一点(x0,y0)求圆上的另外两点(x1,y1,)(x2,y2),使得向量(x1,y1)(x2,y2)和(x0,y0)各个向量两两之间夹角为120度
126
127 此题主要用到向量的叉乘和点乘列出两个二元一次方程组
128
129 1.
130
131 (x0,y0)X (x1,y1) = sin(120)*R^2 (r为圆的半径)
132
133 (x0,y0) * (x1,y1) = cos(120)*R^2
134
135 结果为:
136
137 x1=b*x0-a*y0; a=sin120
138 y1=b*y0+a*x0; b=cos120;
139
140 2.
141
142 (x0,y0)X (x2,y2) = -sin(120)*R^2 (r为圆的半径)
143
144 (x0,y0) * (x2,y2) = cos(120)*R^2
145
146 注:题目假设向量(x1,y1)在向量(x0,y0)逆时针方向 故叉乘结果为正值
147
148 (x2,y2)于(x0,y0)的顺时针方向 故叉乘结果为负值
149
150 #include <stdlib.h>
151 #include <stdio.h>
152 #include <math.h>
153 int main(int argc, char** argv) {
154
155
156 double a,b,sinx,cosx,x0,y0,x1,y1,x2,y2;
157 int t;
158
159 a=sinx=sqrt(3.0)/2;
160 b=cosx=-0.5;
161 scanf("%d",&t);
162 while(t--)
163 {
164 scanf("%lf%lf",&x0,&y0);
165
166 x1=b*x0-a*y0;
167 y1=b*y0+a*x0;
168 x2=b*x0+a*y0;
169 y2=b*y0-a*x0;
170 if(y1<y2||((abs(y1-y2)<0.005)&&x1<x2))
171 {
172 printf("%.3lf %.3lf %.3lf %.3lf\n",x1,y1,x2,y2);
173 }
174 else
175 printf("%.3lf %.3lf %.3lf %.3lf\n",x2,y2,x1,y1);
176
177 }
178
179 return (EXIT_SUCCESS);
180 }