题解:P2632 Explorer

下文用 \(l_1,l_2\) 代指两条直线。

Part1:解析式计算

已知 \((x_a,y_a),(x_b,y_b)\)\(l_1\) 上的点。

那么易得 \(l_1:y=\dfrac{y_b-y_a}{x_b-x_a}x+\dfrac{x_by_a-x_ay_b}{x_b-x_a}\)

同理 \(l_2:y=\dfrac{y_d-y_c}{x_d-x_c}x+\dfrac{x_dy_c-x_cy_d}{x_d-x_c}\)

Part2:考虑暴力

我们还没有想到怎么做。

于是写个 0 分暴力。

对于同一直线上的点,连接最近的点即可。

对于不同直线上的点,暂不考虑,直接暴力连接。

\(O(n+m+nm)\),肯定过不了。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+10;
struct edge{
	int u,v;
	double w;
	friend bool operator<(edge aa,edge bb){
		return aa.w<bb.w;
	}
};
int n,m;
vector<edge> G;
struct DSU{
	int fa[maxn];
	void reset(){
		for(int i=1;i<maxn;i++)fa[i]=i;
	}
	int find(int x){
		if(fa[x]==x)return x;
		return fa[x]=find(fa[x]);
	}
	void merge(int x,int y){
		int fx=find(x),fy=find(y);
		fa[fx]=fy;
	}
	DSU(){reset();}
}d;
double kruskal(){
	sort(G.begin(),G.end());
	int tot=0;
	double val=0;
	for(auto i:G){
		if(d.find(i.u)!=d.find(i.v)){
			d.merge(i.u,i.v);
			tot++;
			val+=i.w;
		}
		if(tot==n+m-1){
			return val;
		}
	}
}
struct dot{double x,y;};
double dis(dot aa,dot bb){return sqrt((aa.x-bb.x)*(aa.x-bb.x)+(aa.y-bb.y)*(aa.y-bb.y));}
vector<dot> la,lb;
struct node{
	double x,y,t;
	friend bool operator<(node aa,node bb){return aa.t<bb.t;}
};
vector<node> ea,eb;
int main(){
	cin>>n>>m;
	int xa,ya,xb,yb,xc,yc,xd,yd;
	cin>>xa>>ya>>xb>>yb>>xc>>yc>>xd>>yd;
	for(int i=1;i<=n;i++){
		double t;
		cin>>t;
		ea.push_back({t*xa+(1.0-t)*xb,t*ya+(1.0-t)*yb,t});
	}
	for(int i=1;i<=m;i++){
		double t;
		cin>>t;
		eb.push_back({t*xc+(1.0-t)*xd,t*yc+(1.0-t)*yd,t});
	}
	sort(ea.begin(),ea.end());
	sort(eb.begin(),eb.end());
	for(int i=0;i<ea.size();i++){
		for(int j=0;j<eb.size();j++){
			G.push_back({i,j+n,dis({ea[i].x,ea[i].y},{eb[j].x,eb[j].y})});
		}
	}
	for(int i=0;i<ea.size()-1;i++){
		G.push_back({i,i+1,dis({ea[i].x,ea[i].y},{ea[i+1].x,ea[i+1].y})});
	}
	for(int i=0;i<eb.size()-1;i++){
		G.push_back({i+n,i+n+1,dis({eb[i].x,eb[i].y},{eb[i+1].x,eb[i+1].y})});
	}
	printf("%0.3lf",kruskal());
	
	return 0;
} 

Part3:优化

同样地,\(l_2\) 上的点也应该连接到 \(l_1\) 上最近的点。

作垂即可。

\(FG\perp AB\)

\(AG=\sqrt{FG^2+AF^2},BG=\sqrt{FG^2+BF^2}\)

由于 \(AF>BF\),所以 \(AG>BG\)

因此对于一个点,我们只需要找到直线上距离垂足最近的点,并与当前点连接即可。

这样边的个数\(O(n+m)\)

本部分建议有兴趣的读者使用 MathDF 完成。

比如我们要过 \(G(x_g,\dfrac{y_d-y_c}{x_d-x_c}x_g+\dfrac{x_dy_c-x_cy_d}{x_d-x_c})\)\(l_1\) 的垂线 \(GF\)

\(GF: y=-\dfrac{x_b-x_a}{y_b-y_a}x+\left[\left( \dfrac{y_d-y_c}{x_d-x_c}+\dfrac{x_b-x_a}{y_b-y_a}\right)x_g+\dfrac{x_dy_c-x_cy_d}{x_d-x_c}\right]\)

设交点 \(F(x_f,y_f)\)

\[\begin{cases} y_f=\dfrac{y_b-y_a}{x_b-x_a}x_f+\dfrac{x_by_a-x_ay_b}{x_b-x_a}\\ \\ y_f=-\dfrac{x_b-x_a}{y_b-y_a}x_f+\left[\left( \dfrac{y_d-y_c}{x_d-x_c}+\dfrac{x_b-x_a}{y_b-y_a}\right)x_g+\dfrac{x_dy_c-x_cy_d}{x_d-x_c}\right] \end{cases}\]

解得:

\[\begin{cases} x_f = \dfrac{ \big[ x_g (y_b - y_a)(y_d - y_c) + x_g (x_b - x_a)(x_d - x_c) + (y_b - y_a)(x_d y_c - x_c y_d) \big](x_b - x_a) - (y_b - y_a)(x_b y_a - x_a y_b)(x_d - x_c) }{(x_d - x_c)\left[ (y_b - y_a)^2 + (x_b - x_a)^2 \right]}\\ y_f = \dfrac{y_b - y_a}{x_b - x_a} \cdot x_f + \dfrac{x_b y_a - x_a y_b}{x_b - x_a}\end{cases}\]

#include<bits/stdc++.h>
#define ly1(x) (k1*x+b1)
#define ly2(x) (k2*x+b2)
using namespace std;
const int maxn=4e5+10;
struct edge{
	int u,v;
	double w;
	friend bool operator<(edge aa,edge bb){
		return aa.w<bb.w;
	}
};
int n,m;
vector<edge> G;
struct DSU{
	int fa[maxn];
	void reset(){
		for(int i=1;i<maxn;i++)fa[i]=i;
	}
	int find(int x){
		if(fa[x]==x)return x;
		return fa[x]=find(fa[x]);
	}
	void merge(int x,int y){
		int fx=find(x),fy=find(y);
		fa[fx]=fy;
	}
	DSU(){reset();}
}d;
double kruskal(){
	sort(G.begin(),G.end());
	int tot=0;
	double val=0;
	for(auto i:G){
		if(d.find(i.u)!=d.find(i.v)){
			d.merge(i.u,i.v);
			tot++;
			val+=i.w;
		}
		if(tot==n+m-1){
			return val;
		}
	}
	return 0.0;
}
struct dot{double x,y;};
double dis(dot aa,dot bb){return sqrt((aa.x-bb.x)*(aa.x-bb.x)+(aa.y-bb.y)*(aa.y-bb.y));}
double dis(double x1,double y1,double x2,double y2){return dis({x1,y1},{x2,y2});}
vector<dot> la,lb;
struct node{
	double x,y,t;
	friend bool operator<(node aa,node bb){return aa.t<bb.t;}
};
vector<node> ea,eb;
vector<pair<double,int>> l1x,l2x;
double k1,k2,b1,b2;
double xa,ya,xb,yb,xc,yc,xd,yd;
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>m;
	cin>>xa>>ya>>xb>>yb>>xc>>yc>>xd>>yd;
	for(int i=1;i<=n;i++){
		double t;
		cin>>t;
		ea.push_back({t*xa+(1.0-t)*xb,t*ya+(1.0-t)*yb,t});
	}
	for(int i=1;i<=m;i++){
		double t;
		cin>>t;
		eb.push_back({t*xc+(1.0-t)*xd,t*yc+(1.0-t)*yd,t});
	}
	if(xb-xa>1e-5)k1=(yb-ya)/(xb-xa)*1.0;else k1=1e18;
	if(xd-xc>1e-5)k2=(yd-yc)/(xd-xc)*1.0;else k2=1e18;
	b1=(xb*ya-xa*yb)/(xb-xa);
	b2=(xd*yc-xc*yd)/(xd-xc);
	sort(ea.begin(),ea.end());
	sort(eb.begin(),eb.end());
	for(int i=0;i<ea.size();i++)l1x.push_back({ea[i].x,i});
	for(int i=0;i<eb.size();i++)l2x.push_back({eb[i].x,i});
	for(int i=0;i<ea.size()-1;i++){
		G.push_back({i,i+1,dis({ea[i].x,ea[i].y},{ea[i+1].x,ea[i+1].y})});
	}
	for(int i=0;i<eb.size()-1;i++){
		G.push_back({i+n,i+n+1,dis({eb[i].x,eb[i].y},{eb[i+1].x,eb[i+1].y})});
	}
#define L1 l1x.begin(),l1x.end()
#define L2 l2x.begin(),l2x.end()
	sort(L1);sort(L2);
#define mp(x,y) make_pair(x,y)
	for(int i=0;i<m;i++){//l2
		double xg=eb[i].x,yg=eb[i].y;
		double czx=((xg*(yb-ya)*(yd-yc)+xg*(xb-xa)*(xd-xc)+(yb-ya)*(xd*yc-xc*yd))*(xb-xa)-(yb-ya)*(xb*ya-xa*yb)*(xd-xc))/((xd-xc)*((yb-ya)*(yb-ya)+(xb-xa)*(xb-xa)));//套公式这一块
		int id=lower_bound(L1,mp(czx,-1))-l1x.begin();
		for(int d=-1;d<=1;d++){//也看它左边和右边的哪个近,不过直接全部连接更好
			int id2=id+d;//delta id
			if((0<=id2&&id2<n)){//isid
				id2=l1x[id2].second;//点的id
				G.push_back({i+n,id2,dis(xg,yg,ea[id2].x,ea[id2].y)});
			}
		}
	}
	for(int i=0;i<n;i++){//l1
		double xg=ea[i].x,yg=ea[i].y;
		double czx=((xg*(yd-yc)*(yb-ya)+xg*(xd-xc)*(xb-xa)+(yd-yc)*(xb*ya-xa*yb))*(xd-xc)-(yd-yc)*(xd*yc-xc*yd)*(xb-xa))/((xb-xa)*((yb-ya)*(yb-ya)+(xb-xa)*(xb-xa)));
		int id=lower_bound(L2,mp(czx,-1))-l2x.begin();
		for(int d=-1;d<=1;d++){
			int id2=id+d;//delta id
			if((0<=id2&&id2<m)){//isid
				id2=l2x[id2].second;//点的id
				G.push_back({i,id2+n,dis(xg,yg,eb[id2].x,eb[id2].y)});
			}
		}
	}
	printf("%0.3lf",kruskal());
	
	return 0;
} 
posted @ 2026-01-22 21:09  zhangruixiang  阅读(1)  评论(1)    收藏  举报