1. 程式人生 > >ZZNU-OJ-2118 -(臺球桌面碰來碰去,求總距離)——模擬到爆炸的不能AC的代碼

ZZNU-OJ-2118 -(臺球桌面碰來碰去,求總距離)——模擬到爆炸的不能AC的代碼

pbo data- spa 包括 oar main 正整數 擁有 algorithm

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 }

ZZNU-OJ-2118 -(臺球桌面碰來碰去,求總距離)——模擬到爆炸的不能AC的代碼