tozangezan's diary

勝手にソースコードをコピペして利用しないでください。

AOJ 1352: Cornering at Poles

中心を移動させる一般的なテクにより、円が障害物で点が動く問題となる。
円と円の交点、点たちからの接線、円と円の共通接線を求めて最短路。移動可能性が本質。

sAPの仕様がよく分からなくて時間を無駄に使った。本当に練習不足である。

#include<stdio.h>
#include<math.h>
#include<vector>
#include<algorithm>
using namespace std;
const double EPS = 1e-10;
const double INF = 1e+10;
const double PI = acos(-1);

vector<Pt> hb;
Pt c[10];
double ijk[11000];
int v[11000];
int main(){
	int a,gx,gy;
	scanf("%d%d%d",&a,&gx,&gy);
	Pt g=Pt((double)gx,(double)gy);
	hb.push_back(Pt(0,0));
	hb.push_back(g);
	for(int i=0;i<a;i++){
		double x,y;
		scanf("%lf%lf",&x,&y);
		c[i]=Pt(x,y);
	}
	for(int i=0;i<a;i++)for(int j=i+1;j<a;j++){
		if((c[i]-c[j]).ABS()<200.0){
			pair<Pt,Pt> it=pCC(c[i],100.0,c[j],100.0);
			hb.push_back(it.first);
			hb.push_back(it.second);
		}
	}
	int rn=hb.size();
	for(int i=0;i<rn;i++){
		for(int j=0;j<a;j++){
			if((hb[i]-c[j]).ABS()>100.0+EPS){
				pair<Pt,Pt> it=tCP(c[j],100.0,hb[i]);
				hb.push_back(it.first);
				hb.push_back(it.second);
			}
		}
	}
	for(int i=0;i<a;i++)for(int j=i+1;j<a;j++){
		Pt v=(c[j]-c[i])*100.0/((c[j]-c[i]).ABS())*Pt(0,1);
		hb.push_back(c[i]+v);
		hb.push_back(c[i]-v);
		hb.push_back(c[j]+v);
		hb.push_back(c[j]-v);
		if((c[i]-c[j]).ABS()>200.0){
			double th=asin(200.0/(c[i]-c[j]).ABS());
			hb.push_back(c[i]+v*Pt(cos(-th),sin(-th)));
			hb.push_back(c[i]-v*Pt(cos(th),sin(th)));
			hb.push_back(c[j]+v*Pt(cos(th),sin(th)));
			hb.push_back(c[j]-v*Pt(cos(-th),sin(-th)));
		}
	}
	int n=hb.size();
	for(int i=1;i<n;i++){
		ijk[i]=999999999.9;
	}
	for(int i=0;i<n;i++){
		double dist=9999999999.9;
		int at=0;
		for(int j=0;j<n;j++){
			if(!v[j]&&dist>ijk[j]){
				dist=ijk[j];at=j;
			}
		}
		v[at]=1;
		for(int j=0;j<n;j++){
			if(v[j]||ijk[j]<ijk[at]+(hb[at]-hb[j]).ABS())continue;
			bool ok=true;
			for(int k=0;k<a;k++){
				if(dSP(hb[at],hb[j],c[k])<100.0-EPS)ok=false;
			}
			if(ok){
				ijk[j]=ijk[at]+(hb[at]-hb[j]).ABS();
			}
		}
		int on=0;
		for(int j=0;j<a;j++){
			if(100.0-EPS<(c[j]-hb[at]).ABS()&&(c[j]-hb[at]).ABS()<100.0+EPS)on+=(1<<j);
		}
		for(int j=0;j<n;j++){
			if(v[j])continue;
			for(int k=0;k<a;k++){
				if(!(on&(1<<k)))continue;
				if(100.0-EPS>(c[k]-hb[j]).ABS()||(c[k]-hb[j]).ABS()>100.0+EPS)continue;
				bool ok1=true;
				bool ok2=true;
				for(int l=0;l<a;l++){
					if(k==l)continue;
					if((c[k]-c[l]).ABS()>200.0)continue;
					pair<Pt,Pt> tmp=pCC(c[k],100.0,c[l],100.0);
					if(sAP(hb[at]-c[k],hb[j]-c[k],tmp.first-c[k])>0)ok1=false;
					if(sAP(hb[j]-c[k],hb[at]-c[k],tmp.first-c[k])>0)ok2=false;
					if(sAP(hb[at]-c[k],hb[j]-c[k],tmp.second-c[k])>0)ok1=false;
					if(sAP(hb[j]-c[k],hb[at]-c[k],tmp.second-c[k])>0)ok2=false;
				//	if(i==1&&j==70&&l==1)printf("%f %f %f\n",(hb[at]-c[k]).arg(),(hb[j]-c[k]).arg(),(tmp.first-c[k]).arg());
				}
				
				if(ok1){
					double th=(hb[j]-c[k]).arg()-(hb[at]-c[k]).arg();
					if(th<0)th+=PI*2;
					Pt chk=c[k]+(hb[at]-c[k])*Pt(cos(th/2),sin(th/2));
					bool ok=true;
					for(int l=0;l<a;l++)if((chk-c[l]).ABS()<100.0-EPS)ok=false;
					if(ok){
			//			if(i==1)printf("%d (%f, %f) %d 1\n",at,hb[j].x,hb[j].y,k);
						ijk[j]=min(ijk[j],ijk[at]+100.0*th);
					}
				}
				if(ok2){
					double th=(hb[at]-c[k]).arg()-(hb[j]-c[k]).arg();
					if(th<0)th+=PI*2;
					Pt chk=c[k]+(hb[j]-c[k])*Pt(cos(th/2),sin(th/2));
					bool ok=true;
					for(int l=0;l<a;l++)if((chk-c[l]).ABS()<100.0-EPS)ok=false;
					if(ok){
				//		if(i==1)printf("%d (%f, %f) %d 2\n",at,hb[j].x,hb[j].y,k);
						ijk[j]=min(ijk[j],ijk[at]+100.0*th);
					}
				}
			}
		}
	//	if(i==1)for(int j=0;j<hb.size();j++)printf("(%f, %f): %f\n",hb[j].x,hb[j].y,ijk[j]);	
	}
	//for(int i=0;i<hb.size();i++)printf("(%f, %f): %f\n",hb[i].x,hb[i].y,ijk[i]);
	if(ijk[1]<99999999.9)printf("%.12f\n",ijk[1]);
	else printf("0.0\n");
}