“我真难,真的,”mxy抬起他没有神采的眼睛来,接着说。“我单知道半平面交可以往凸包里放圆,放两个一样的就找最远的一对端点;我不知道凹多边形就会死掉。我一个多小时就开了K题,感觉和poj风水是一个题,就粘了份半平面交板子。板子很靠谱的,遇见的题都能过;交上去wa1。我就继续改精度,交上去,又wa1了,要重新读遍题。我读完题,感觉没有错,去网上找了份新板子,只见又wa1了,没有生命迹象了。我是不是想的太简单了;画了几张图,果然出现了恐怖的事情。我急了,在那挠头发,过了好半会儿,想到了jls18年出的多校,也是凹多边形往里塞圆的。我觉得稳了,必过,再不过我吃屎。再提交;竟然tle了,想了半天,原来那道题的复杂度是O(n³)的。……” 他接着但是呜咽,说不出成句的话来。
神经病这个题真是。
我把浑身本领施展完了开始从题目条件出发,刚想了一下就感觉不太对。30m????
这树才4米啊???
『当时和队友得出的结论是,凹多边形一定有解,凸包的话用我原来的缩边半平面交就行』
上面的结论显然是对的,问题在于如何找凹多边形的解。
想到的是『找到一个凹点两侧的凸点,角平分线画圆即可』。
可惜的是时间不够调试了,没过。
赛后看qls代码发现了更巧妙的做法。看所有的凸点是否可行然后找一对可行的即可。(其实本质上差不多?)
补完看题解。四个点及以上一定有解。wslndmnmntys
从头被治到尾,太治傻逼了。
主要是题目给人的感觉太熟悉了,,很容易就想到半平面交和jls的那个多边形放圆了,都试完了才回头挖掘题目所给的条件,可惜时间来不及了。
#include <bits/stdc++.h>
using namespace std;
typedef double db;
const db eps=1e-6;
const db R = 4000.0;
int sign(db k){
if (k>eps) return 1; else if (k<-eps) return -1; return 0;
}
int cmp(db k1,db k2){return sign(k1-k2);}
int inmid(db k1,db k2,db k3){return sign(k1-k3)*sign(k2-k3)<=0;}// k3 在 [k1,k2] 内
struct point{
db x,y;
point operator + (const point &k1) const{return (point){k1.x+x,k1.y+y};}
point operator - (const point &k1) const{return (point){x-k1.x,y-k1.y};}
point operator * (db k1) const{return (point){x*k1,y*k1};}
point operator / (db k1) const{return (point){x/k1,y/k1};}
int operator == (const point &k1) const{return cmp(x,k1.x)==0&&cmp(y,k1.y)==0;}
// 逆时针旋转
point turn(db k1){return (point){x*cos(k1)-y*sin(k1),x*sin(k1)+y*cos(k1)};}
point turn90(){return (point){-y,x};}
bool operator < (const point k1) const{
int a=cmp(x,k1.x);
if (a==-1) return 1; else if (a==1) return 0; else return cmp(y,k1.y)==-1;
}
db abs(){return sqrt(x*x+y*y);}
db abs2(){return x*x+y*y;}
db dis(point k1){return ((*this)-k1).abs();}
point unit(){db w=abs(); return (point){x/w,y/w};}
void scan(){double k1,k2; scanf("%lf%lf",&k1,&k2); x=k1; y=k2;}
void print(){printf("%.8lf %.8lf
",x,y);}
db getw(){return atan2(y,x);}
point getdel(){if (sign(x)==-1||(sign(x)==0&&sign(y)==-1)) return (*this)*(-1); else return (*this);}
int getP() const{return sign(y)==1||(sign(y)==0&&sign(x)==-1);}
};
int inmid(point k1,point k2,point k3){return inmid(k1.x,k2.x,k3.x)&&inmid(k1.y,k2.y,k3.y);}
db cross(point k1,point k2){return k1.x*k2.y-k1.y*k2.x;}
db dot(point k1,point k2){return k1.x*k2.x+k1.y*k2.y;}
db rad(point k1,point k2){return atan2(cross(k1,k2),dot(k1,k2));}
// -pi -> pi
int compareangle (point k1,point k2){//极角排序+
return k1.getP()<k2.getP()||(k1.getP()==k2.getP()&&sign(cross(k1,k2))>0);
}
point proj(point k1,point k2,point q){ // q 到直线 k1,k2 的投影
point k=k2-k1;return k1+k*(dot(q-k1,k)/k.abs2());
}
point reflect(point k1,point k2,point q){return proj(k1,k2,q)*2-q;}
int clockwise(point k1,point k2,point k3){// k1 k2 k3 逆时针 1 顺时针 -1 否则 0
return sign(cross(k2-k1,k3-k1));
}
int checkLL(point k1,point k2,point k3,point k4){// 求直线 (L) 线段 (S)k1,k2 和 k3,k4 的交点
return cmp(cross(k3-k1,k4-k1),cross(k3-k2,k4-k2))!=0;
}
point getLL(point k1,point k2,point k3,point k4){
db w1=cross(k1-k3,k4-k3),w2=cross(k4-k3,k2-k3); return (k1*w2+k2*w1)/(w1+w2);
}
db disSP(point k1,point k2,point q){
point k3=proj(k1,k2,q);
if (inmid(k1,k2,k3)) return q.dis(k3); else return min(q.dis(k1),q.dis(k2));
}
int n,can[2551];
point p[2551],ans[2551];
bool init(int id){
point y=p[id],x=p[(id-1+n)%n],z=p[(id+1)%n];
if(cross(z-y,y-x)>0)return false;
db j = abs(rad(z-y,x-y));
db dis = R/sin(j/2);
ans[id] = (((z-y).unit()+(x-y).unit())/2).unit()*dis+y;
// x.print();y.print();z.print();ans[id].print();
for(int i=0;i<n;i++) {
// printf("%.11f
",disSP(p[i], p[(i + 1) % n], ans[id]));
if (disSP(p[i], p[(i + 1) % n], ans[id]) < R-eps)
return false;
}
return true;
}
int main() {
scanf("%d", &n);
for (int i = 0; i < n; i++)scanf("%lf%lf", &p[i].x, &p[i].y);
reverse(p, p + n);
// can[0]=init(0);
for(int i=0;i<n;i++)can[i]=init(i);//printf("%d
",can[i]);
for(int i=0;i<n;i++)
if(can[i])
for(int j=i+1;j<n;j++)
if(can[j])
if(ans[i].dis(ans[j])>=R*2-eps){
ans[i].print();
ans[j].print();
exit(0);
}
printf("impossible
");
}
//
//}//