题面
http://codeforces.com/contest/1019/problem/D
题解
如果我们确定了三角形的底边,就同时确定了顶点到底边的距离。
我们想要实现的是依次枚举底边时,所有的点都已经按照到此底边的距离(分正负)排好序,这样就可以通过二分查找判答案了。
考虑对于两个点u,v,底边l,u到l和v到l的距离的大小关系。发现这两者的大小关系当且仅当l与uv连线平行或共线时发生变化。
因此,算法的流程就出来了:将所有的底边按极角排序。一开始,将所有点按照y坐标排序,并记为序列S。依次枚举排好序后的底边,设这个底边是原图中的点u,v连接而成,那么此时u,v在S中一定相邻。交换它们。依次进行,则S就是我们时刻维护的,将所有点以到当前底边距离为关键字的有序序列,在S中二分查找判答案即可。
时间复杂度(O(n^2 log n))。
代码
#include<bits/stdc++.h>
using namespace std;
#define ld long double
#define rg register
#define In inline
const ld eps = 1e-9;
const int N = 2000;
In int read(){
int s = 0,ww = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-')ww = -1;ch = getchar();}
while('0' <= ch && ch <= '9'){s = 10 * s + ch - '0';ch = getchar();}
return s * ww;
}
In void write(int x){
if(x < 0)putchar('-'),x = -x;
if(x > 9)write(x / 10);
putchar('0' + x % 10);
}
In int sgn(ld x){return x < -eps ? -1 : x > eps;}
In ld sqr(ld x){return x * x;}
struct vec{
ld x,y;
vec(){}
vec(ld _x,ld _y){x = _x,y = _y;}
In friend vec operator + (vec a,vec b){
return vec(a.x + b.x,a.y + b.y);
}
In friend vec operator - (vec a,vec b){
return vec(a.x - b.x,a.y - b.y);
}
In friend vec operator * (vec a,ld k){
return vec(a.x * k,a.y * k);
}
In friend vec operator / (vec a,ld k){
return vec(a.x / k,a.y / k);
}
In friend ld Cross(vec a,vec b){
return a.x * b.y - a.y * b.x;
}
In friend ld Dot(vec a,vec b){
return a.x * b.x + a.y * b.y;
}
In friend bool InUpper(vec a){
int k;
return ((k=sgn(a.y)) > 0 || (k==0&&sgn(a.x)>0));
}
In friend ld len(vec a){
return sqrt(sqr(a.x) + sqr(a.y));
}
In friend vec Rot90(vec a){
return vec(a.y,-a.x);
}
};
struct seg{
vec A,B;
seg(){}
seg(vec _A,vec _B){A = _A,B = _B;}
In friend ld len(seg a){
return len(a.B - a.A);
}
};
vec Upward(vec p,ld d,vec v){
ld Len = len(v);
return p + v * d / Len;
}
In ld dis(vec p,seg a){
return Cross(a.B - p,a.A - p) / len(a);
}
pair<int,int>pr[N*N+5];
vec p[N+5],s[N+5];
int rk[N+5];
ld S;
int n;
In bool cmp1(pair<int,int>i,pair<int,int>j){
seg a = seg(p[i.first],p[i.second]),b = seg(p[j.first],p[j.second]);
int k1 = InUpper(a.B-a.A),k2 = InUpper(b.B-b.A);
if(k1 != k2)return k1 < k2;
return sgn(Cross(a.B-a.A,b.B-b.A)) > 0;
}
In bool cmp2(vec a,vec b){
int k;
if((k=sgn(a.y-b.y)) != 0)return k > 0;
return sgn(a.x - b.x) > 0;
}
seg curp;
In bool cmp3(vec a,vec b){
return dis(a,curp) > dis(b,curp);
}
void PrAns(vec a,vec b,vec c){
puts("Yes");
write((int)round(a.x)),putchar(' '),write((int)round(a.y)),putchar('
');
write((int)round(b.x)),putchar(' '),write((int)round(b.y)),putchar('
');
write((int)round(c.x)),putchar(' '),write((int)round(c.y)),putchar('
');
}
int main(){
n = read();cin>>S;//scanf("%llf",&S);
for(rg int i = 1;i <= n;i++){
int x = read(),y = read();
p[i] = vec(x,y);
}
sort(p + 1,p + n + 1,cmp2);
for(rg int i = 1;i <= n;i++)rk[i] = i,s[i] = p[i];
int cnt = 0;
for(rg int i = 1;i <= n;i++)
for(rg int j = 1;j <= n;j++){
if(i == j || InUpper(p[j]-p[i]))continue;
pr[++cnt] = make_pair(i,j);
}
sort(pr + 1,pr + cnt + 1,cmp1);
for(rg int k = 1;k <= cnt;k++){
int i = pr[k].first,j = pr[k].second;
curp = seg(p[i],p[j]);
swap(s[rk[i]],s[rk[j]]);
swap(rk[i],rk[j]);
ld h = 2 * S / len(curp.B - curp.A);
int pos = lower_bound(s + 1,s + n + 1,Upward(curp.A,h,Rot90(curp.B-curp.A)),cmp3) - s;
if(sgn(fabs(dis(s[pos],curp))-h) == 0){
PrAns(s[pos],p[i],p[j]);
return 0;
}
pos = lower_bound(s + 1,s + n + 1,Upward(curp.A,-h,Rot90(curp.B-curp.A)),cmp3) - s;
if(sgn(fabs(dis(s[pos],curp))-h) == 0){
PrAns(s[pos],p[i],p[j]);
return 0;
}
}
puts("No");
return 0;
}