最远距离 北邮2012网研院复试上机题

102. 最远距离

时间限制1000 ms     内存限制 65536 KB    

题目描述

正义的伙伴褋祈和葬仪社的机器人Fuyuneru正在被邪恶的GHQ部队追杀。眼看着快要逃不掉了,祈就把重要的东西塞到了机器人体内,让它先跑,自己吸引火力。

假设Fuyuneru带上东西开始逃跑时所处的点为原点,朝向为正北。操纵FuyuNeru的指令有如下四种:

right X: X是1-359之间的整数,Fuyuneru的前进方向顺时针转X度。

left X: X是1-359之间的整数,Fuyuneru的前进方向逆时针转X度。

forward X: X是整数(0<=X<=1000),Fuyuneru向当前朝向前进X米。

backward X: X是整数(0<=X<=1000),Fuyuneru向当前朝向后退X米。

现在祈向Fuyuneru体内输入了N(1<=N<=50)个这样的指令。可是由于此前Fuyuneru被GHQ部队击中,它出了一点小问题:这N个指令执行的顺序是不确定的。

问:Fuyuneru最远可能逃出多远?

即,Fuyuneru在执行完N条指令之后,距离原点最远的可能距离是多少?

输入格式

第一行是一个整数T,代表测试数据有T组。

每组测试数据中,第一行是一个整数N,代表指令有N条;

随后紧跟N行,每一行代表一个指令(格式保证是上述四种中的一种,数据保证合法)

输出格式

对于每组数据,输出一行:最远的可能逃亡距离,精确到小数点后3位。

输入样例

  1. 3
  2. 3
  3. forward 100
  4. backward 100
  5. left 90
  6. 4
  7. left 45
  8. forward 100
  9. right 45
  10. forward 100
  11. 6
  12. left 10
  13. forward 40
  14. right 30
  15. left 10
  16. backward 4
  17. forward 4

输出样例

  1. 141.421
  2. 200 .000
  3. 40 .585

 

最远距离为,向前走之后,找到一个向后走的时候向前走的方向尽可能处在180°上的方向。

比如,向前走100米,然后向右转180°,然后向后走100米,然后随意旋转,这样就距离起点最远,200米。

所以问题转化为,找到一种旋转组合,使得尽可能旋转180°。

然后利用a^2+b^2-2abcosC=c^2求出最远距离

 

对于求出旋转角度组合,设向右为正,假设输入顺序:60°,30°,10°,等等

我们读入60°的时候,从(0+60°)-(360°+60°)开始枚举,首先标记60°为访问过,vis[60]=1,即我们可以旋转出60°这个角度来,然后访问余下的角度,如果访问过x°,if(vis[x]==1),那么我们标记x+60°为也访问过,即x+60°这个角度也是可以被访问到的,vis[x+60]=1。

比如,当我们按顺序第二个读入30°的时候,vis[30]=1,在(0+60°)-(360°+60°)枚举的过程中,枚举到30°+30°的时候,因为vis[30+30]==1,所以,vis[60+30]=1。

然后我们只要不断更新,最接近180的vis[],然后计算即可。

 

 

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<cstdlib>
  5. #include<cstdio>
  6. #include<cmath>
  7. #include<set>
  8. #define Pi acos(-1.0)
  9. using namespace std;
  10. double dis(double a,double b,double Ang) {
  11. return sqrt(a*a+b*b -2*a*b* cos(Ang/ 180*Pi));
  12. }
  13. int main() {
  14. int i,j,t,n,vis[ 360],val,minA,rec[ 360]; //minA是和180°最接近的角度,vis用来记录是否可以到达该角度,rec用来记录当前角度是否被使用过
  15. multiset< int>turn; //来存旋转角度,向右为正
  16. int up,down; //前进和后退
  17. string s;
  18. for( cin>>t;t--;){
  19. turn.clear();
  20. up=down= 0;
  21. memset(vis, 0, sizeof vis);
  22. for( cin>>n;n--;){
  23. cin>>s>>val;
  24. if(s== "forward")up+=val;
  25. else if(s== "backward")down+=val;
  26. else{
  27. if(s== "right")turn.insert(val);
  28. else turn.insert( 360-val);
  29. }
  30. }
  31. multiset< int>::iterator it;
  32. vis[ 0]= 1;
  33. for(it=turn.begin();it!=turn.end();it++){
  34. //printf("it:%d\n",*it);
  35. memset(rec, 0, sizeof rec);
  36. for(i= 0;i< 360;i++){
  37. int tmp=(i+*it)% 360;
  38. if(rec[i]== 0&&(vis[i])&&vis[tmp]== 0){
  39. vis[tmp]=rec[tmp]= 1;
  40. }
  41. }
  42. }
  43. minA= 180; //防止没有旋转指令
  44. for(i= 0;i< 360;i++)
  45. if(vis[i])
  46. if( abs( 180-i)<minA)
  47. minA= abs( 180-i);
  48. //printf("minA:%d\n",minA);
  49. printf( "%.3lf\n",dis(up,down, 180-minA));
  50. }
  51. return 0;
  52. }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值