cf 1252 I 路径规划

貌似是比较防AK的几何模板题。LRJ书上的提到运动规划模型是它的简化版,思路也可以参考。

题意:平面上给定 n (n<=50) 个大小不同的圆,要求给出一条从起点到终点的折线路径,使路径与圆不相交,且不超出给定区域。坐标范围均在0~1000内。

比较容易想到只要在所有可能的切线上走一定能走到终点。题目也刚好规定与圆相切不算相交,证实了整个想法。然后就是套模板生成所有切线,共生成O(n^2)条。注意如果切线被割断,则丢弃。然后延长切线至尽可能长,顶到边界或其他圆。然后从起点bfs一遍就可以了,bfs时暴力枚举所有线段,判断是否有交即可。最后答案对路径上的线算一遍交点。
这里共线的情况也不必考虑,直接视为不相交。
如果这题圆与边界相交,还要注意圆把边界割为几段的情况。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3.  
  4. typedef long double db;
  5.  
  6. const db eps=1e-7,PI=acos(-1);
  7.  
  8. bool eq(db x){return fabs(x)<eps;}
  9. int sgn(db x){
  10. 	if (x<-eps) return -1;
  11. 	return x>eps;
  12. }
  13.  
  14. #define Vec const vec&
  15. #define Point const point&
  16. struct vec{
  17. 	db x,y;
  18. 	vec(db theta){x=cosl(theta),y=sinl(theta);}
  19. 	vec(db x, db y):x(x),y(y){}
  20. 	vec(){}
  21. 	vec operator+(Vec v)const{return {x+v.x,y+v.y};}
  22. 	vec operator-(Vec v)const{return {x-v.x,y-v.y};}
  23. 	vec operator*(db a)const{return {x*a,y*a};}
  24. 	vec operator/(db a)const{return {x/a,y/a};}
  25. 	db operator|(Vec v)const{return x*v.x+y*v.y;}
  26. 	db operator&(Vec v)const{return x*v.y-y*v.x;}
  27. 	db operator!()const{return sqrt(x*x+y*y);}
  28. 	bool operator==(Vec v)const{return eq(x-v.x) && eq(y-v.y);}
  29. 	vec l90()const{return {-y,x};}
  30. 	db ang()const{return atan2l(y,x);}
  31. 	void rd(){double tx,ty;scanf("%lf%lf",&tx,&ty); x=tx,y=ty;}
  32. 	void prt(){printf("(%f,%f)",(double)x,(double)y);}
  33. };
  34. typedef vec point;
  35.  
  36. vec lineInt(Vec p, Vec vp, Vec q, Vec vq){
  37. 	db t=(vq & p-q)/(vp&vq);
  38. 	return p+vp*t;
  39. }
  40. db lineDis(Point p, Point s, Vec v){
  41. 	return fabs(v & p-s)/!v;
  42. }
  43. bool rectCover(Point a1, Point a2, Point b1, Point b2){return 
  44. 	min(a1.x,a2.x)<=max(b1.x,b2.x)+eps &&
  45. 	min(b1.x,b2.x)<=max(a1.x,a2.x)+eps &&
  46. 	min(a1.y,a2.y)<=max(b1.y,b2.y)+eps &&
  47. 	min(b1.y,b2.y)<=max(a1.y,a2.y)+eps;
  48. }
  49. //test if segment A1-A2 B1-B2 is cross
  50. int segCross(Point a1, Point a2, Point b1, Point b2){
  51. 	if (!rectCover(a1,a2,b1,b2)) return 0; //not necessary
  52. 	db c1=sgn(a2-a1&b1-a1), c2=sgn(a2-a1&b2-a1);
  53. 	db c3=sgn(b2-b1&a1-b1), c4=sgn(b2-b1&a2-b1);
  54. 	if (c1*c2>0 || c3*c4>0) //no cross
  55. 		return 0; 
  56. 	if (c1==0 && c2==0||c3==0 && c4==0) //segment on same line
  57. 		return 0; 
  58. 	if (c1*c2<0 && c3*c4<0) return 1; //normal cross
  59. 	return 2; //a point on line
  60. }
  61.  
  62. #define Circle const circle &
  63. struct circle{
  64. 	vec c; db r;
  65. 	vec angle(db theta)const{return c+vec(theta)*r;}
  66. }cir[51];
  67.  
  68. int cirTang(vec p, Circle c, vec *ans){
  69. 	db d=!(c.c-p);
  70. 	//if (sgn(d-c.r)<=0) return 0;
  71. 	if (eq(d-c.r)){
  72. 		ans[0]=p;
  73. 		return 1;
  74. 	}
  75. 	db base=(p-c.c).ang();
  76. 	db ang=acos(c.r/d);
  77. 	ans[0]=c.angle(base-ang);
  78. 	ans[1]=c.angle(base+ang);
  79. 	return 2;
  80. }
  81.  
  82. int cirTang(circle A, circle B, point *a, point *b){
  83. 	int cnt=0;
  84. 	//if (A.c==B.c && eq(A.r-B.r)) return -1;
  85. 	if (A.r<B.r) swap(A,B),swap(a,b);
  86. 	db d=!(A.c-B.c);
  87. 	db diff=A.r-B.r, sum=A.r+B.r;
  88. 	//if (sgn(d-diff)<0) return 0;
  89. 	db base=(B.c-A.c).ang();
  90. 	//if (eq(d-diff)){
  91. 	//	a[0]=A.angle(base);
  92. 	//	b[0]=a[0];
  93. 	//	return 1;
  94. 	//}
  95. 	db ang=acos((A.r-B.r)/d);
  96. 	a[cnt]=A.angle(base+ang); b[cnt++]=B.angle(base+ang);
  97. 	a[cnt]=A.angle(base-ang); b[cnt++]=B.angle(base-ang);
  98. 	ang=acos((A.r+B.r)/d);
  99. 	a[cnt]=A.angle(base+ang); b[cnt++]=B.angle(PI+base+ang);
  100. 	a[cnt]=A.angle(base-ang); b[cnt++]=B.angle(PI+base-ang);
  101. 	return 4;
  102. }
  103.  
  104. int segInt(Vec a, Vec b, Circle c, pair<db,db> &ans){
  105. 	vec v=b-a, u=a-c.c;
  106. 	db e=v|v,f=v|u*2,g=(u|u)-c.r*c.r;
  107. 	db delta=f*f-4*e*g;
  108. 	if (sgn(c.r-lineDis(c.c,a,b-a))<=0) return 0;
  109. 	db t1=(-f-sqrt(delta))/(2*e);
  110. 	db t2=(-f+sqrt(delta))/(2*e);
  111. 	ans={t1,t2};
  112. 	return 2;
  113. }
  114. int lineInt(Vec a, Vec b, Circle c, point *ans){
  115. 	vec v=b-a, u=a-c.c;
  116. 	db e=v|v,f=v|u*2,g=(u|u)-c.r*c.r;
  117. 	db delta=f*f-4*e*g;
  118. 	if (sgn(c.r-lineDis(c.c,a,b-a))<=0) return 0;
  119. 	db t1=(-f-sqrt(delta))/(2*e);
  120. 	db t2=(-f+sqrt(delta))/(2*e);
  121. 	vec a1=a+v*t1, a2=a+v*t2;
  122. 	int cnt=0;
  123. 	ans[cnt++]=a1; ans[cnt++]=a2;
  124. 	return 2;
  125. }
  126.  
  127. struct line{
  128. 	vec p1,p2;
  129. }li[50010];
  130. int n;
  131. vec tmp[4],tmp2[4],__[4]; line bod[4];vec kp[4];
  132. bool inbod(Vec p){
  133. 	return p.x>=kp[2].x-eps && p.x<=kp[3].x+eps && p.y>=kp[2].y-eps && p.y<=kp[3].y+eps;
  134. }
  135.  
  136. bool expli(vec &p1, vec &p2){
  137. 	db l=-1e20,r=1e20;
  138. 	if (!inbod(p1) || !inbod(p2)) return 0;
  139. 	for (int i=0;i<n;i++){
  140. 		pair<db,db> t;
  141. 		if (segInt(p1,p2,cir[i],t)==0) continue;
  142. 		if (t.second>eps && t.second<1-eps || t.first>eps && t.first<1-eps) return 0;
  143. 		if (t.first>0.5) r=min(r,t.first);
  144. 		else l=max(l,t.second);
  145. 	}
  146. 	for (int i=0;i<4;i++){
  147. 		vec vp=p2-p1, vq=bod[i].p2-bod[i].p1;
  148. 		if (!eq(vp&vq)){
  149. 			db t=(vq & p1-bod[i].p1)/(vp&vq);
  150. 			if (t>0.5) r=min(r,t);
  151. 			else l=max(l,t);
  152. 		}
  153. 	}
  154. 	vec vp=p2-p1;
  155. 	p2=p1+vp*r;
  156. 	p1=p1+vp*l;
  157. 	return 1;
  158. }
  159.  
  160.  
  161. vec lineInt(line l1, line l2){
  162. 	return lineInt(l1.p1,l1.p2-l1.p1,l2.p1,l2.p2-l2.p1);
  163. }
  164.  
  165. int qu[50010],pre[50010],qh,qt,lic;
  166. bool vis[50010];
  167. set<int> lend;
  168. double ttr;
  169. int main(){
  170. 	cin>>n; 
  171. 	for (int i=0;i<4;i++) kp[i].rd();
  172. 	swap(kp[0],kp[2]);swap(kp[3],kp[1]);
  173. 	bod[0]={{kp[2].x,kp[2].y},{kp[3].x,kp[2].y}};
  174. 	bod[1]={{kp[2].x,kp[3].y},{kp[3].x,kp[3].y}};
  175. 	bod[2]={{kp[2].x,kp[2].y},{kp[2].x,kp[3].y}};
  176. 	bod[3]={{kp[3].x,kp[2].y},{kp[3].x,kp[3].y}};
  177. 	for (int i=0;i<n;i++)
  178. 		cir[i].c.rd(),scanf("%lf",&ttr),cir[i].r=ttr;
  179. 	tmp[0]=kp[0],tmp[1]=kp[1];
  180. 	if (expli(tmp[0],tmp[1])) return puts("0"),0;
  181. 	for (int i=0;i<n;i++){
  182. 		for (int j=i+1;j<n;j++){
  183. 			cirTang(cir[i],cir[j],tmp,tmp2);
  184. 			for (int k=0;k<4;k++){
  185. 				if (expli(tmp[k],tmp2[k])) li[lic++]={tmp[k],tmp2[k]};
  186. 			}
  187. 		}
  188. 	}
  189. 	for (int i=0;i<2;i++)
  190. 		for (int j=0;j<n;j++){
  191. 			cirTang(kp[i],cir[j],tmp);
  192. 			for (int k=0;k<2;k++){
  193. 				vec tkp=kp[i];
  194. 				if (tmp[0]==tkp) tmp[0]=tkp+(tkp-cir[i].c).l90();
  195. 				if (expli(tmp[k],tkp)){
  196. 					if (i==0) pre[qt]=-1,qu[qt++]=lic,vis[lic]=1;
  197. 					else lend.insert(lic);
  198. 					li[lic++]={tmp[k],tkp};
  199. 				}
  200. 			}
  201. 		}
  202. 	sort(cir,cir+n,[](Circle a, Circle b){return a.c.x<b.c.x;});
  203. 	db cur=kp[2].x;
  204. 	line bo=bod[0];
  205. 	for (int i=0;i<n;i++){
  206. 		if (lineInt(bo.p1,bo.p2,cir[i],tmp))
  207. 			li[lic++]={{cur,kp[2].y},{tmp[0].x,kp[2].y}},
  208. 			cur=tmp[1].x;
  209. 	}
  210. 	li[lic++]={{cur,kp[2].y},{kp[3].x,kp[2].y}};
  211.  
  212. 	cur=kp[2].x;
  213. 	bo=bod[1];
  214. 	for (int i=0;i<n;i++){
  215. 		if (lineInt(bo.p1,bo.p2,cir[i],tmp))
  216. 			li[lic++]={{cur,kp[3].y},{tmp[0].x,kp[3].y}},
  217. 			cur=tmp[1].x;
  218. 	}
  219. 	li[lic++]={{cur,kp[3].y},{kp[3].x,kp[3].y}};
  220.  
  221. 	sort(cir,cir+n,[](Circle a, Circle b){return a.c.y<b.c.y;});
  222. 	cur=kp[2].y;
  223. 	bo=bod[2];
  224. 	for (int i=0;i<n;i++){
  225. 		if (lineInt(bo.p1,bo.p2,cir[i],tmp))
  226. 			li[lic++]={{kp[2].x,cur},{kp[2].x,tmp[0].y}},
  227. 			cur=tmp[1].y;
  228. 	}
  229. 	li[lic++]={{kp[2].x,cur},{kp[2].x,kp[3].y}};
  230.  
  231. 	cur=kp[2].y;
  232. 	bo=bod[3];
  233. 	for (int i=0;i<n;i++){
  234. 		if (lineInt(bo.p1,bo.p2,cir[i],tmp))
  235. 			li[lic++]={{kp[3].x,cur},{kp[3].x,tmp[0].y}},
  236. 			cur=tmp[1].y;
  237. 	}
  238. 	li[lic++]={{kp[3].x,cur},{kp[3].x,kp[3].y}};
  239. //	for (int i=0;i<qt;i++) cout<<qu[i]<<' ';cout<<'\n';
  240. //	for (auto i:lend) cout<<i<<' ';cout<<'\n';
  241. //	for (int i=0;i<lic;i++){cout<<i<<' '; li[i].p1.prt(); putchar(' '); li[i].p2.prt(); cout<<'\n';}
  242. 	while (qh<qt){
  243. 		int u=qu[qh];
  244. 		if (lend.count(u)){
  245. 			vector<vec> ans;
  246. 			int su=qh;
  247. 			while (~pre[su])
  248. 				ans.push_back(lineInt(li[qu[su]],li[qu[pre[su]]]))
  249. //				,cout<<qu[su]<<' '
  250. 				,su=pre[su];
  251. //			cout<<'\n'<<lineDis(cir[0].c,ans[0],kp[1]-ans[0])<<'\n';
  252. 			cout<<ans.size()<<'\n';
  253. 			for (int i=0;i<ans.size();i++)
  254. 				for (int j=i+1;j<ans.size();j++)
  255. 					assert(!(ans[i]==ans[j]));
  256. 			reverse(begin(ans),end(ans));
  257. 			for (auto it:ans)
  258. 				printf("%.15f %.15f\n",(double)it.x,(double)it.y);
  259. 			return 0;
  260. 		}
  261. 		for (int i=0;i<lic;i++) if (!vis[i] && segCross(li[u].p1,li[u].p2,li[i].p1,li[i].p2)){
  262. 			pre[qt]=qh;
  263. 			qu[qt++]=i;
  264. 			vis[i]=1;
  265. 		}
  266. 		qh++;
  267. 	}
  268.  
  269. 	return 0;
  270. }

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注