我之前写过一个余弦定理的证明及其应用的博客,但是因为那时候自己特别的菜,而且原博客没有加 LaTeX \LaTeX LATEX,而且很多地方有描述不明确的地方,现在来修一下
还是那张图,来自百度百科
余弦定理的内容是,对于任意一个三角形,满足
a
2
=
b
2
+
c
2
−
2
b
c
⋅
cos
A
b
2
=
a
2
+
c
2
−
2
a
c
⋅
cos
B
c
2
=
a
2
+
b
2
−
2
a
b
⋅
cos
C
a^2=b^2+c^2-2bc\cdot \cos A \\ b^2=a^2+c^2-2ac\cdot \cos B \\ c^2=a^2+b^2-2ab\cdot \cos C
a2=b2+c2−2bc⋅cosAb2=a2+c2−2ac⋅cosBc2=a2+b2−2ab⋅cosC
证明其实很简单
上面那个图里面就能看出来
∵
A
B
=
c
,
B
D
=
c
⋅
cos
B
,
A
D
=
c
⋅
sin
B
,
C
D
=
a
−
c
⋅
cos
B
,
Rt
Δ
A
D
C
∴
c
2
⋅
sin
2
B
+
(
a
−
c
⋅
cos
B
)
2
=
b
2
c
2
⋅
sin
2
B
+
a
2
−
2
a
c
⋅
cos
B
+
c
2
⋅
sin
2
B
=
b
2
a
2
+
c
2
−
2
a
c
⋅
cos
B
=
b
2
\because AB=c,BD=c\cdot \cos B,AD=c\cdot \sin B,CD=a-c\cdot \cos B,\text{Rt}_\Delta ADC \\ \therefore c^2\cdot \sin^2 B+(a-c\cdot \cos B)^2=b^2 \\ c^2\cdot \sin^2B+a^2-2ac\cdot \cos B+c^2\cdot\sin^2B=b^2 \\ a^2+c^2-2ac\cdot\cos B=b^2
∵AB=c,BD=c⋅cosB,AD=c⋅sinB,CD=a−c⋅cosB,RtΔADC∴c2⋅sin2B+(a−c⋅cosB)2=b2c2⋅sin2B+a2−2ac⋅cosB+c2⋅sin2B=b2a2+c2−2ac⋅cosB=b2
另外两个也同理
当然,还有一种非常简便的证法,是利用向量(
v
e
c
t
o
r
vector
vector)解决的
向量,手写体记做
a
⃗
\vec{a}
a,打印体有时也记做a
向量内积,
a
⃗
⋅
b
⃗
=
∣
a
⃗
∣
⋅
∣
b
⃗
∣
⋅
cos
θ
\vec{a}\cdot\vec{b}=|\vec{a}|\cdot|\vec{b}|\cdot\cos\theta
a⋅b=∣a∣⋅∣b∣⋅cosθ
其中
θ
\theta
θ表示两个向量的夹角,不懂可以百度优先搜索,话说这个高中课本上会讲吧
我们把他重新定向一下,那么
a
⃗
+
b
⃗
=
c
⃗
a
⃗
=
c
⃗
−
b
⃗
a
⃗
2
=
(
c
⃗
−
b
⃗
)
2
∣
a
⃗
∣
2
=
∣
b
⃗
∣
2
+
∣
c
⃗
∣
2
−
2
b
⃗
⋅
c
⃗
a
2
=
b
2
+
c
2
−
2
∣
b
⃗
∣
⋅
∣
c
⃗
∣
⋅
cos
θ
a
2
=
b
2
+
c
2
−
2
b
c
⋅
cos
θ
\vec{a}+\vec{b}=\vec{c} \\ \vec{a}=\vec{c}-\vec{b} \\ \vec{a}^2=(\vec{c}-\vec{b})^2 \\ |\vec{a}|^2=|\vec{b}|^2+|\vec{c}|^2-2\vec{b}\cdot\vec{c} \\ a^2=b^2+c^2-2|\vec{b}|\cdot|\vec{c}|\cdot \cos\theta \\ a^2=b^2+c^2-2bc\cdot\cos\theta
a+b=ca=c−ba2=(c−b)2∣a∣2=∣b∣2+∣c∣2−2b⋅ca2=b2+c2−2∣b∣⋅∣c∣⋅cosθa2=b2+c2−2bc⋅cosθ
其它的也一样,我不会告诉你我theta角标错了因为是盗的图
余弦定理是解三角形中的一个非常重要的定理,配合正弦定理应用可以解决对任意三角形知三求三的问题,是非常重要的一个定理
那么余弦定理在OI中又有什么应用呢?
题目描述(这里不是向量…)
有一条豪华游轮(其实就是条小木船),这种船可以执行
4
4
4种指令:
r i g h t right right X X X : 其中 X X X是一个 1 1 1到 719 719 719的整数,这个命令使得船顺时针转动X度。
l e f t left left X X X : 其中 X X X是一个 1 1 1到 719 719 719的整数,这个命令使得船逆时针转动X度。
f o r w a r d forward forward X X X : 其中 X X X是一个整数( 1 1 1到 1000 1000 1000),使得船向正前方前进X的距离。
b a c k w a r d backward backward X X X : 其中 X X X是一个整数( 1 1 1到 1000 1000 1000),使得船向正后方前进X的距离。
随意的写出了 n n n个命令,找出一个种排列命令的方法,使得船最终到达的位置距离起点尽可能的远。
输入输出格式
输入格式:
第一行一个整数
n
n
n(
1
≤
n
≤
50
1 \leq n \leq 50
1≤n≤50),表示给出的命令数。
接下来 n n n行,每行表示一个命令。
输出格式:
一个浮点数,能够走的最远的距离,四舍五入到
6
6
6位小数。
这道题我们看到之后很快就能够反映出来,这个地方需要做一个贪心
因为多次拐弯肯定比一次的要近,所以我们让 f o r w a r d forward forward走完,然后尽量转 180 180 180度,然后把 b a c k w a r d backward backward走完,这时候起点和终点之间的距离就是要算的答案了
那么我们怎么来算他能最多转多少度才能让这个度数和
180
180
180度的差最小呢?
我们可以运用背包的思想
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示前i个转圈的指令,能不能转到j度,转移其实很简单,大概是这样的:
for(int i=1,i<=anglecnt;i++)
for(int j=0;j<=360;j++){
if(f[i-1][j]){
f[i][j]=true;
f[i][(j+angle[i]+360)%360]=true;
}
}
那好了,我们现在知道了旋转角度,知道了两边的边长,那么我们就可以使用余弦定理了啊
printf("%.6lf\n",sqrt(a*a+b*b-2*a*b*cos(degree*pi/180)));
注意 C + + C++ C++中三角函数运用的是弧度制
全代码大概是这样的
# include <cstdio>
# include <algorithm>
# include <cstring>
# include <cmath>
# include <climits>
# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=55;
const double pi=3.14159265358979;
int n,go,back,angle[N],a,b,degree=INT_MAX;
bool f[N][1005];
char s[N];
int main()
{
scanf("%d",&n);
Rep(i,1,n){
int x;
scanf("%s%d",s,&x);
if(s[0]=='f') a+=x;
if(s[0]=='b') b+=-x;
if(s[0]=='l') angle[++angle[0]]=x;
if(s[0]=='r') angle[++angle[0]]=-x;
}
f[0][0]=true;
Rep(i,1,angle[0])
Rep(j,0,360){
if(f[i-1][j]){
f[i][j]=true;
f[i][(j+angle[i]+360)%360]=true;
}
}
Rep(i,0,360)
if(f[angle[0]][i]) degree=min(degree,abs(180-i));
printf("%.6lf\n",sqrt(a*a+b*b-2*a*b*cos(degree*pi/180)));
return 0;
}