【UER #9】赶路

【UER #9】赶路

-----一定有解。。

\(x_1\leq x_i\leq x_n\)

将中间的点按照\((x_i,y_i)\)排序,然后依次连过去即可

\[\ \]

\(x_1=y_1=0\),四个象限均存在点

将所有点极角排序,然后走一圈即可

\[\ \]

\(O(n\log n)\)

不妨设\(x_1<x_n\)

将\(1,n\)以外所有点分成三部分,即左边| 1 | 中间 | n | 右边

左边右边考虑极角排序转圈走,中间按照\((x_i,y_i)\)走

发现两边极角排序之后转圈走不一定能够走到中间去,可能会与转圈时的路径相交

但是实际上画图就会发现,如果顺时针走的路径会相交,逆时针走一定不相交

因此对于左右枚举顺时针还是逆时针即可,4中情况,每种\(O(n)\)检查线段相交

总能构造一组合法解

预处理需要排序,因此复杂度为\(O(n\log n)\)

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef pair <int,int> Pii;
#define reg register
#define mp make_pair
#define pb push_back
#define Mod1(x) ((x>=P)&&(x-=P))
#define Mod2(x) ((x<0)&&(x+=P))
#define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }

char IO;
template <class T=int> T rd(){
	T s=0; int f=0;
	while(!isdigit(IO=getchar())) f|=IO=='-';
	do s=(s<<1)+(s<<3)+(IO^'0');
	while(isdigit(IO=getchar()));
	return f?-s:s;
}

const int N=510,INF=1e9+10;
const db eps=1e-7;

int n,m;
struct Node{
	db x,y;
	Node(){}
	Node(db x,db y):x(x),y(y){ }
	bool operator < (const Node __) const { return x!=__.x?x<__.x:y<__.y; }
	Node operator - (const Node &t) const { return Node(x-t.x,y-t.y); }
	db operator * (const Node &t) const { return x*t.x+y*t.y; }
	db operator ^ (const Node &t) const { return x*t.y-y*t.x; }
	void turn(db t){
		db a=x*cos(t)-y*sin(t),b=x*sin(t)+y*cos(t);
		x=a,y=b;
	}
	db tan() const { return atan2(x,y); }
} A[N];
int Cross(int x,int y,int a,int b){
	if(((A[x]-A[y])^(A[a]-A[b]))==0) return 0;
	db l=(A[a]-A[x])^(A[y]-A[x]),r=(A[b]-A[x])^(A[y]-A[x]);
	if((l<0)^(r>0)) return 0;
	swap(a,x),swap(b,y);
	l=(A[a]-A[x])^(A[y]-A[x]),r=(A[b]-A[x])^(A[y]-A[x]);
	if((l<0)^(r>0)) return 0;
	return 1;
}

int L[N],LC,R[N],RC,T[N],TC;
int P[N];

int Work(){
	int C=0;
	P[++C]=1;
	rep(i,1,LC) P[++C]=L[i];
	rep(i,1,TC) P[++C]=T[i];
	rep(i,1,RC) P[++C]=R[i];
	P[++C]=n;
	if(LC) rep(i,2,LC) if(Cross(P[LC+1],P[LC+2],P[i],P[i-1])) return 0;
	if(RC) drep(i,n,n-RC+2) if(Cross(P[n-RC],P[n-RC-1],P[i],P[i-1])) return 0;
	return 1;
}
void Solve(){
	rep(i,0,1) {
		rep(j,0,1) {
			if(Work()) {
				rep(i,1,n) printf("%d ",P[i]);
				puts("");
				return;
			}
			reverse(R+1,R+RC+1);
		}
		reverse(L+1,L+LC+1);
	}
}

int main(){
	rep(kase,1,rd()){
		rep(i,1,n=rd()) A[i].x=rd(),A[i].y=rd();
		db t=1.0*(rand()+2)/(rand()+2);
		rep(i,1,n) A[i].turn(t);
		if(A[1].x>A[n].x) rep(i,1,n) A[i].x=-A[i].x;
		LC=RC=TC=0;
		rep(i,2,n-1) if(A[i].x<A[1].x-eps) L[++LC]=i;
		else if(A[i].x-eps>A[n].x) R[++RC]=i;
		else T[++TC]=i;
		sort(T+1,T+TC+1,[&](int x,int y){ return A[x].x<A[y].x; });
		sort(L+1,L+LC+1,[&](int x,int y){ return (A[x]-A[1]).tan()<(A[y]-A[1]).tan(); });
		sort(R+1,R+RC+1,[&](int x,int y){ return (A[x]-A[n]).tan()<(A[y]-A[n]).tan(); });
		Solve();
	}
}
上一篇:E. Colorings and Dominoes(Educational Codeforces Round 107 (Rated for Div. 2))题解


下一篇:「USACO 2021.1 Platinum」Sum of Distances