ZZNU-OJ-2118 -(台球桌面碰来碰去,求总距离)——模拟到爆炸的不能AC的代码

2118 : 早安晚安,不如我先入土为安

题目描述

spring比较喜欢玩台球,因为看着台球在桌子上碰来碰去很有意思(台球撞壁反弹,入射角等于反射角),每次完美的台球入洞,都能体现他数学天才的能力。机房的大佬们当然不承认spring能力强,而是认为每次都是运气而已。

spring很不服气,但又打不过机房大佬,争执过程中聪明的渣渣宥终于想到了完美的办法,那也就是建立数学模型,交给脸红脖子粗的spring来解决。

题目给出一组(x,y),表示矩形的四个点分别为(0,0)(x,0)(0,y)(x,y),构成一个密闭的矩形,只有一个入口(也是唯一的出口)在原点也就是(0,0),假设一个点在原点按照角度(ay=bx)射入矩形中,所拥有的动能为E,每次接触墙壁并反弹所消耗的动能为W,如果射到除原点以外的三个顶点,将原路返回,并且消耗动能W。忽略摩擦力的影响,求出球在矩阵中运动的位移之和,保留两位有效数字。

输入

输入为六个正整数x,y,a,b,E,W。x,y,a,b均小于2000,E,W属于int

输出

求出球在矩阵中运动的位移之和,保留两位有效数字。

样例输入

复制

1 1 1 1 1 1
1 1 1 1 2 1

样例输出

复制

1.41
2.83

模拟了四个小时,WA了,瞬间原地爆炸了;

我把错误代码放着了,纪念一下下。

思路或许是对的,可能那个细节出了问题23333

放一组后台数据,就当是一丢丢正确的事情吧——

INPUT

1 3 3 1 17 1

OUTPUT

17.92

以以下是错误代码,好心人可以瞧瞧bug——


以以下是错误代码,好心人可以瞧瞧bug——

  1 #include <iostream>
  2 #include<stdio.h>
  3 #include<string.h>
  4 #include<string>
  5 #include<algorithm>
  6 #define ll long long
  7 using namespace std;
  8 #include<math.h>
  9 #define N 1008
 10 #define M 10008
 11 #define dinf 1000000.0
 12 double X,Y,a,b,E,W;
 13 const double eps=1e-10;
 14 #define PI 3.14159265358
 15 struct Point
 16 {
 17     double x,y;
 18     Point(double x=0.0,double y=0.0):x(x),y(y) {}
 19 } p[5];
 20 typedef Point Vector;
 21 struct line
 22 {
 23     Point e,f;
 24     double k,b;
 25 } L0,L[5];
 26
 27 Vector operator-(Point a,Point b)
 28 {
 29     return Vector(a.x-b.x,a.y-b.y);
 30 }
 31 bool operator==(Point a,Point b)
 32 {
 33     return (fabs(a.x-b.x)<eps)&&(fabs(a.y-b.y)<eps);
 34 }
 35 double cross(Vector t,Vector f) //计算两个向量的叉乘 之模
 36 {
 37     return (t.x*f.y-t.y*f.x);
 38 }
 39 double cross1(Point  e, Point  f,  Point  g)///向量ef与向量eg的叉积,左边为负值, 锐角为正值
 40 {
 41     return cross(f-e,g-e);
 42 }
 43
 44 int factcover(  Point  e,  Point  f,  Point  g,  Point  h)///判断两个线段是否相交, 如果不包括端点 直接<0 包括端点为<=minn(极小值)
 45 {
 46     if(min(e.x,f.x)<=max(g.x,h.x)&&///要避免某一边的端点值  在另一边的延长线上
 47             max(e.x,f.x)>=min(g.x,h.x)&&
 48             min(e.y,f.y)<=max(g.y,h.y)&&
 49             max(e.y,f.y)>=min(g.y,h.y)&& ///<=也可以;前四行 大大于小, 大大于小, 大大于小, 大大于小
 50             cross1(e,f,g)*cross1(e,f,h)<0&&   ///两条边相交   端点判断容易出错  便需要两条边同时进行; ///己方向量加一异点, 此行相交时结果为负值或0
 51             cross1(e,g,h)*cross1(f,g,h)<0)    ///如果两者共点  返回值也是1///轮流己方一点指向两个异点, 此行相交时结果为负值或0
 52         return 1;          ///0 0 1 1 3 3 4 4 返回0      0 0 9 9 3 3 4 4 返回1
 53     return 0;              ///0 0 3 3 3 3 4 4 返回1     0 0 3 3 3 3 4 5 返回1
 54 }
 55 int fact_corner(  Point  e,  Point  f,  Point  g,  Point  h)///判断两个线段是否相交, 如果不包括端点 直接<0 包括端点为<=minn(极小值)
 56 {
 57     if(min(e.x,f.x)<=max(g.x,h.x)&&///要避免某一边的端点值  在另一边的延长线上
 58             max(e.x,f.x)>=min(g.x,h.x)&&
 59             min(e.y,f.y)<=max(g.y,h.y)&&
 60             max(e.y,f.y)>=min(g.y,h.y)&& ///<=也可以;前四行 大大于小, 大大于小, 大大于小, 大大于小
 61             cross1(e,f,g)*cross1(e,f,h)<=eps&&   ///两条边相交   端点判断容易出错  便需要两条边同时进行; ///己方向量加一异点, 此行相交时结果为负值或0
 62             cross1(e,g,h)*cross1(f,g,h)<=eps)    ///如果两者共点  返回值也是1///轮流己方一点指向两个异点, 此行相交时结果为负值或0
 63         return 1;          ///0 0 1 1 3 3 4 4 返回0      0 0 9 9 3 3 4 4 返回1
 64     return 0;              ///0 0 3 3 3 3 4 4 返回1     0 0 3 3 3 3 4 5 返回1
 65 }
 66 void init(double x,double y)     //四个顶点,四条边,初始点p0
 67 {
 68     p[1]=Point(0,0);
 69     p[2]=Point(0,y);
 70     p[3]=Point(x,y);
 71     p[4]=Point(x,0);
 72
 73     L[1].e=p[1],L[1].f=p[2];
 74     L[1].k=dinf;
 75     L[2].e=p[2],L[2].f=p[3];
 76     L[2].k=0;
 77     L[3].e=p[3],L[3].f=p[4];
 78     L[3].k=dinf;
 79     L[4].e=p[4],L[4].f=p[1];
 80     L[4].k=0;
 81
 82 }
 83 double Dot(Vector A,Vector B)   ///向量之间的点积
 84 {
 85     return A.x*B.x+A.y*B.y;
 86 }
 87 double Length(Vector A)     //利用点积求向量长度
 88 {
 89     return sqrt(Dot(A,A));
 90 }
 91
 92 double DisToLine(Point P,Point A,Point B)  //点到直线的距离
 93 {
 94     Vector v1=B-A,v2=P-A;
 95     return fabs(cross(v1,v2))/Length(v1);
 96 }
 97 void factk(line &s)   //计算并更改S的斜率,并将线段的边长延伸M倍
 98 {
 99     /* if(fabs(s.e.x-s.f.x)<1e-8) //斜率不存在
100      {
101          s.e.y+=M;s.f.y-=M;
102      }
103      else{*/
104     // s.k=(s.e.y-s.f.y)/(s.e.x-s.f.x);
105     s.e.x+=1.0*M;
106     s.e.y+= s.k * M;
107     s.f.x-=1.0*M;
108     s.f.y-= s.k * M;
109
110 }
111 void launch(line &s,Point &p0,int begnum, double &ans)    //反射,并返回碰撞数据
112 {
113     //求触碰边(角落),返回 反射后的射线S的 p0、k、b系数;
114     int flag=0;
115
116     for(int i=1; i<=4; i++) //先检查是否撞到了四条边上,再检查是否撞到了四个点上
117     {
118         if(i!=begnum&&factcover(s.e,s.f,L[i].e,L[i].f)==1)
119         {
120             flag=i;
121             break;
122         }
123     }
124     if(flag!=0)   //本次弹射将撞到 第flag的边上
125     {
126         double newk,newb;
127         cout<<"边 "<<flag;
128         if(flag==1||flag==3)  //两条竖着的边
129         {
130             double x=L[flag].e.x;
131             double y=s.k*x+s.b;
132             ans+=Length(p0-Point(x,y));
133             p0=Point(x,y);
134
135             newk=-1*s.k;
136             newb=y-x*newk;
137         }
138         else  //两条横着的矩形边
139         {
140             double y=L[flag].e.y;
141             double x=(y-s.b)/s.k;
142             ans+=Length(p0-Point(x,y));
143             p0=Point(x,y);
144
145             newk=-1*s.k;
146             newb=y-x*newk;
147         }
148
149         s.k=newk;
150         s.b=newb;///更新反射后的射线S 的k和b
151     }
152     else
153     {
154         if(begnum>4)
155             begnum-=4;//本次弹射将撞到 第flag的角落上
156         int a[]= {0,  1,4, 1,2, 2,3, 3,4};
157         int vis[5]= {0}; //标记
158         int t1,t2;
159         t1=a[begnum*2-1];
160         t2=a[begnum*2];
161         vis[t1]=vis[t2]=1;//标记的点
162         ///找到可以弹射到的第k个角落
163         for(int j=1; j<=7; j+=2)
164         {
165             if(vis[a[j]]==0&&vis[a[j+1]]==0)
166             {
167                 flag=(j+1)/2;
168                 break;
169             }
170         }
171
172         cout<<"角 "<<flag;
173         ans+=Length(p0-p[flag]);
174         p0=p[flag];
175
176         s.k=-s.k;
177         s.b=s.b;///碰撞到四个角后原路返回,k变化,b不变!
178     }
179
180 }
181 int main()
182 {
183
184     while(scanf("%lf",&X)!=EOF)
185     {
186         scanf("%lf%lf%lf%lf%lf",&Y,&a,&b,&E,&W);
187         init(X,Y);
188         int Time=0;
189
190         Point p0=Point(0,0);  //初始起点和射线
191         line s;
192         s.k=b/a;
193         s.b=0.0;
194         double ans=0.0;
195
196         while(E>0)
197         {
198             ++Time;
199             int begnum=-1;
200             for(int i=1; i<=4; i++) //四个角编号为1+4--4+4
201             {
202                 if(p[i]==p0)
203                     begnum=i+4;
204             }
205             for(int i=1; begnum==-1&&i<=4; i++) //四条边为1--4
206             {
207                 if(DisToLine(p0,L[i].e,L[i].f)<eps)
208                 {
209                     begnum=i;
210                 }
211             }
212             printf(" p0= %lf,%lf  s.k=%lf s.b=%lf total_ans:%lf\n",p0.x,p0.y,s.k,s.b,ans);
213             if(Time>1&&begnum==5)break;///从源点冲出去了
214
215             s.e=p0;
216             s.f=p0;//当前射线方程;
217             factk(s);//由点扩展成线
218
219             launch(s,p0,begnum,ans);//发射小球,计算出新的碰撞点存入p0中,并更改a,b
220             E-=W;//减去动能W
221         }
222         printf("%.2lf\n",ans);
223     }
224
225     return 0;
226 }

原文地址:https://www.cnblogs.com/zhazhaacmer/p/9378963.html

时间: 2024-10-08 15:12:16

ZZNU-OJ-2118 -(台球桌面碰来碰去,求总距离)——模拟到爆炸的不能AC的代码的相关文章

ZZNU - OJ - 2080 : A+B or A-B【暴力枚举】

2080 : A+B or A-B(点击左侧标题进入zznu原题页面) 时间限制:1 Sec 内存限制:0 MiB提交:8 答案正确:3 提交 状态 讨论区 题目描述 Give you three strings s1, s2 and s3. These strings contain only capital letters A,B,C,D,E. The letters that appear in the string represent a number from 0 to 9.Each

scu oj 4445 Right turn 2015年四川省赛J题(模拟题)

一般的模拟题.对于出现过的每一个x建立一个set 集合,对于y也如此.然后查找要走到哪个点即可,主要要对状态记录,判断是否无线循环,否者出现无线循环的情况,就tle了. #include<stdio.h> #include<string.h> #include<iostream> #include<string> #include<queue> #include<cmath> #include<map> #include&

关于对碰奖的解析!

因为最近在编程有关对碰奖的业务,所以研究了一下对碰奖. 一.什么是双轨制 给大家介绍双轨制度,易通电讯奖励制度是每个人都有两个区,左区(A区)和右区(B区),也就是说紧挨着你的只会有两个客户,如下图,比如A和B都是您的客户. 如果您除了这两个客户,又推荐了客户,怎么办?那只能往A或者B的下面任意一点放置,如上图. 比如我现在把我第三个客户放在A的A区,我管这个客户叫A1,那么就如上图所示,A1也有自己的两个区,现在我的第四个客户位置就可以选择上图中标明"空"的任意位置. 通过这张图,我

台球游戏的核心算法和AI(2)

前言: 最近研究了box2dweb, 觉得自己编写Html5版台球游戏的时机已然成熟. 这也算是圆自己的一个愿望, 一个梦想. 承接该序列的相关博文: • 台球游戏核心算法和AI(1) 同时结合html5的学习笔记: • box2dweb 学习笔记--sample讲解  这篇文章, 具体讲解台球游戏的box2d模型抽象, 并给出一个初步版本. 演示: 台球游戏的雏形如下所示: 该台球游戏, 改编自box2dweb的demo程序, 可用鼠标拖动球来移动. 代码的下载链接: http://pan.b

基于Seajs的可控台球碰撞游戏

前言 不记得哪个黑色星期五,贪吃鱼基本完工的时候,产品突然增加需求,要求金币扔出去后不消失,互相可碰撞,其最终结果还要由服务器控制(没错,至今做的所有游戏都有幕后黑手,=W=). 对于碰撞以前只写过一个球到处碰墙壁的,小球之间的碰撞倒是没有接触,想到他们碰撞过程中的角度变化.速度分配,就不敢往下想了,于是马上想到box2d这个牛逼哄哄的引擎. 但是,使用物理引擎虽然高效.逼真,但所有碰撞都是不可控,包括最终的落点.所以引擎不能解决这次遇到的需求. 不能用引擎,咱自己写也不怕,反正当年物理和高数都

java图形界面写个小桌面,内置简单小软件

一.做个这样的效果,双击图标打开相应的应用 二.主界面类,使用JavaSwing的JDesktopPane类创建这个桌面 package com.swing; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.event.MouseAdapte

虚拟桌面技术的初步探讨

[文章标题]: 虚拟桌面技术的初步探讨  [文章作者]:  newjueqi  [作者邮箱]: [email protected][作者QQ号]: 190678908[编写语言]:VC++6.0[操作平台]: XP-SP2[作者声明]:感觉到这是一种非常有意思的技术,这篇就当成是学习笔记吧!本人只是感兴趣,没有其它目的,失误之处敬请给位大侠原谅! 本文曾发表于看学论坛http://bbs.pediy.com/showthread.PHP?t=82537                      

nyist oj 38 布线问题 (最小生成树 prim)

布线问题 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 南阳理工学院要进行用电线路改造,现在校长要求设计师设计出一种布线方式,该布线方式需要满足以下条件: 1.把所有的楼都供上电. 2.所用电线花费最少 输入 第一行是一个整数n表示有n组测试数据.(n<5) 每组测试数据的第一行是两个整数v,e. v表示学校里楼的总个数(v<=500) 随后的e行里,每行有三个整数a,b,c表示a与b之间如果建铺设线路花费为c(c<=100).(哪两栋楼间如果没有指明花费

CSU OJ 1112机器人的指令 (湖南省12年省赛题)

 Welcome to CSU Online Judge! 1112: 机器人的指令 Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 274  Solved: 97 [Submit][Status][Web Board] Description 数轴原点有一个机器人.该机器人将执行一系列指令,你的任务是预测所有指令执行完毕之后它的位置. ·LEFT:往左移动一个单位 ·RIGHT: 往右移动一个单位 ·SAME AS i: 和第i 条执行相同的