[计算几何+最短路]P1027 [NOIP2001 提高组] Car 的旅行路线

传送门

首先,这道题明显需要计算几何的相关知识,我输入了一个城市的三个点,怎么知道另一个点呢?

看一张图。

image

是的,我只需要找到一个是 \(\frac{\pi}{2}\) 的角度,然后利用向量的平行就 ok 了。

怎么找 \(\frac{\pi}{2}\) 的角呢,只需要利用 \(k\) 是负倒数就 ok 了。

特别注意,如果是一条如 \(x=a,a\in R\) 的直线,我们无法用斜截式表示,所以我用了一个变量专门去存是否垂直于 \(x\) 轴。

同时,这个图建图需要将每一个飞机场连起来,然后用距离公式:

\(D(A,B)\) 为点 \(A\) 到点 \(B\) 的距离

\[D(A,B)=\sqrt{(A_x-B_x)^2+(A_y-B_y)^2} \]

然后只需要反手一个堆优化的 dijk 就解决了,代码细节很多。

#include <bits/stdc++.h>
#define debug puts("I ak IOI several times");
#define pb push_back
using namespace std;
template <typename T>inline void read(T& t){
    t=0; register char ch=getchar(); register int fflag=1;
    while(!('0'<=ch&&ch<='9')){if(ch=='-') fflag=-1;ch=getchar();}
    while(('0'<=ch&&ch<='9')){t=((t<<1)+(t<<3))+ch-'0'; ch=getchar();} t*=fflag;
}
template <typename T,typename... Args> inline void read(T& t, Args&... args){
    read(t);read(args...);
}
template <typename T>inline void write(T x){
    if(x<0) putchar('-'),x=~(x-1); int s[40],top=0;
    while(x) s[++top]=x%10,x/=10; if(!top) s[++top]=0;
    while(top) putchar(s[top--]+'0');
}
const int MAXN=10000,MAXM=1000000;
const double EPS=1e-7;
int T,head[MAXN],cnt,sta,en,n,m;
struct Point{
	int x,y;
	Point(){
		x=0;y=0;
	}
	void R(){read(x),read(y);}
	void print(){
		cout<<x<<' '<<y<<endl; 
	} 
};
struct Line{
	Point A,B;
	double k,b;
	bool Ver=0,Lev=0;
	Line(){
		k=0,b=0,Ver=0,Lev=0;
	}
	void Calc(){
		if(A.y==B.y){
			Ver=1;
			return;
		}
		if(A.x==B.x){
			Lev=1;
			return;
		}
		k=(A.y-B.y)*1.0/(A.x-B.x*1.0);
		b=B.y*1.0-k*B.x;
	}
};
bool ver(Line x,Line y){
	if(x.Ver&&y.Lev) return 1;
	if(x.Lev&&y.Ver) return 1;
	if(x.Ver||x.Lev||y.Ver||y.Lev) return 0;
	return (abs(x.k+1.0/(y.k))<=EPS);
}
struct City{
	Point a,b,c,d;
	double cost;
	double dist(Point x,Point y){ return sqrt((x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y)); }
	void calca(){
		d.x=a.x+c.x-b.x;
		d.y=a.y+c.y-b.y;
	}
	Point ccalc(int whi){
		if(whi==1) return a;
		if(whi==2) return b; 
		if(whi==3) return c;
		if(whi==4) return d; 
	}
	void R(){
		a.R();b.R();c.R(); cin>>cost;
		Line AB,BC,AC;
		AB.A=AC.A=a; BC.A=AB.B=b; BC.B=AC.B=c;
		AB.Calc(); BC.Calc(); AC.Calc();
		//调整到 a 对 c, b 对 d
		if(ver(AB,BC)){
			// Do nothing
		}else
			if(ver(AB,AC)){
				//cout<<AB.Ver<<' '<<AC.Lev<<' '<<AB.Lev<<' '<<AB.Ver<<endl; 
				swap(a,b);
			}
			else if(ver(BC,AC)) swap(b,c);
		//调整结束,使用平行四边形牛刀公式 
		calca();
	}
}cit[MAXN];
struct Edge{
	int to;double val;int nxt;
}e[MAXM];
void add(int x,int y,double val){
	//建立双向边 
	e[++cnt]={y,val,head[x]};
	head[x]=cnt;
	e[++cnt]={x,val,head[y]};
	head[y]=cnt;
	return;
}
void intt(){
	memset(e,0,sizeof(e)); cnt=0;
	read(n,m,sta,en);
	for(int i=1;i<=n;++i){
		cit[i].R();
	/*	cit[i].a.print();
		cit[i].b.print();
		cit[i].c.print();
		cit[i].d.print();*/
	}
	// 这边建一手图 
	for(int i=1;i<=n;++i){
		//首先是一个城市内建图
		for(int ddx=1;ddx<=4;++ddx)
			for(int ddy=ddx+1;ddy<=4;++ddy)
				if(ddx!=ddy) add(i*4+ddx,i*4+ddy,cit[i].dist(cit[i].ccalc(ddx),cit[i].ccalc(ddy))*cit[i].cost);
		for(int j=i+1;j<=n;++j)
			//然后在各个飞机场建图
			for(int dx=1;dx<=4;++dx)
				for(int dy=1;dy<=4;++dy)
					add(i*4+dx,j*4+dy,cit[i].dist(cit[i].ccalc(dx),cit[j].ccalc(dy))*m); 
	}
	return;
}
struct Node{
	double val;
	int to;
	bool operator < (const Node &node) const{
		return val>node.val;
	}
};
double minn(double a,double b,double c,double d){
	if(a<b&&a<c&&a<d) return a;
	if(b<a&&b<c&&b<d) return b;
	if(c<a&&c<b&&c<d) return c;
	if(d<a&&d<b&&d<c) return d;
}
priority_queue<Node>Q;
double dis[MAXN];
bool vis[MAXN];
void solve(){
	intt();
	while(!Q.empty())Q.pop();
	memset(dis,98,sizeof(dis));
	memset(vis,0,sizeof(vis));
	for(int dx=1;dx<=4;++dx) dis[sta*4+dx]=0,Q.push({0,sta*4+dx});
	while(!Q.empty()){
		int u=Q.top().to; Q.pop();
		//cout<<u<<endl;
		if(vis[u]) continue;
		vis[u]=1;
		for(int i=head[u];i;i=e[i].nxt){
			int v=e[i].to;
			if(dis[v]>dis[u]+e[i].val){
				dis[v]=dis[u]+e[i].val;
				Q.push({dis[v],v});
			}
		} 
	}
	cout<<fixed<<setprecision(1)<<minn(dis[en*4+1],dis[en*4+2],dis[en*4+3],dis[en*4+4])<<endl;
	return;
}
int main(){
	read(T);
	while(T--) solve();
    return 0;
}
//Welcome back,Chtholly.

image

posted @ 2021-12-28 20:33  Mercury_City  阅读(91)  评论(0编辑  收藏  举报