P2625 豪华游轮
题目传送门
这是一道贪心为主,数学为辅的题目。
根据题目,我们可以轻松得到下列结论:先向前走(走完\(forward\)),然后通过旋转把船身尽可能调转方向(接近\(180°\)),接着走掉剩余的(\(backward\))。我们知道,为了尽可能远离出发点,必须不走回头路,所以第一,三步没问题。而对于偏转多少度,通过余弦定理可以知道,两邻边一定的情况下,设夹角为\(\alpha\),\(\cos\alpha\)越小,第三边越大,对于区间\([0,\pi]\),\(\cos\alpha\)单调递减,所以当\(\alpha=\pi\)时,\(\cos\alpha\)有最小值,第三边有最大值。
那么我们只需要考虑怎么组合能使得偏转角度接近\(180\),那么就用01背包解决,最后求距离用余弦定理解决即可。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=50+10;
int qian,hou;
int n;
int a[400],f[20000+10];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
string s;cin>>s;
int x;cin>>x;
if(s=="forward")qian+=x;
if(s=="backward")hou+=x;
if(s=="left")x%=360,a[x]++;
if(s=="right")x%=360,a[360-x]++;
}
f[0]=1;
for(int i=0;i<360;i++)
while(a[i]--)
for(int j=20000;j>=0;j--)
if(f[j])f[j+i]++;
int minn=0x7fffffff;
for(int i=1;i<=20000;i++)
if(f[i])minn=min(minn,abs(i%360-180));
if(minn==0){
cout<<qian+hou<<".000000"<<endl;
return 0;
}
cout<<fixed<<setprecision(6)<<sqrt((double)qian*qian+(double)hou*hou-2*(double)qian*(double)hou*cos((double)(180-minn)*M_PI/180))<<endl;
return 0;
}