我之前寫過一個餘弦定理的證明及其應用的博客,但是因爲那時候自己特別的菜,而且原博客沒有加,而且很多地方有描述不明確的地方,現在來修一下
還是那張圖,來自百度百科
餘弦定理的內容是,對於任意一個三角形,滿足
證明其實很簡單
上面那個圖裏面就能看出來
另外兩個也同理
當然,還有一種非常簡便的證法,是利用向量()解決的
向量,手寫體記做,打印體有時也記做a
向量內積,
其中表示兩個向量的夾角,不懂可以百度優先搜索,話說這個高中課本上會講吧
我們把他重新定向一下,那麼
其它的也一樣,我不會告訴你我theta角標錯了因爲是盜的圖
餘弦定理是解三角形中的一個非常重要的定理,配合正弦定理應用可以解決對任意三角形知三求三的問題,是非常重要的一個定理
那麼餘弦定理在OI中又有什麼應用呢?
題目描述(這裏不是向量…)
有一條豪華遊輪(其實就是條小木船),這種船可以執行種指令:
: 其中是一個到的整數,這個命令使得船順時針轉動X度。
: 其中是一個到的整數,這個命令使得船逆時針轉動X度。
: 其中是一個整數(到),使得船向正前方前進X的距離。
: 其中是一個整數(到),使得船向正後方前進X的距離。
隨意的寫出了個命令,找出一個種排列命令的方法,使得船最終到達的位置距離起點儘可能的遠。
輸入輸出格式
輸入格式:
第一行一個整數(),表示給出的命令數。
接下來行,每行表示一個命令。
輸出格式:
一個浮點數,能夠走的最遠的距離,四捨五入到位小數。
這道題我們看到之後很快就能夠反映出來,這個地方需要做一個貪心
因爲多次拐彎肯定比一次的要近,所以我們讓走完,然後儘量轉度,然後把走完,這時候起點和終點之間的距離就是要算的答案了
那麼我們怎麼來算他能最多轉多少度才能讓這個度數和度的差最小呢?
我們可以運用揹包的思想
表示前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)));
注意中三角函數運用的是弧度制
全代碼大概是這樣的
# 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;
}