【经典】半平面交求解方程组——poj1755

神坑,精度要调到1e-10,板子没问题

/*
二分距离,凸包所有边往左平移这个距离,半平面交后看是否还有核存在 
*/

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
#define N 205

typedef double db;
const db eps=1e-10;
const db inf=1e10;
const db pi=acos(-1.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(){}
    point(db x,db y):x(x),y(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);}
    db abs(){return sqrt(x*x+y*y);}
    db abs2(){return x*x+y*y;}
    db dis(point k1){return ((*this)-k1).abs();}
    int getP() const{return sign(y)==1||(sign(y)==0&&sign(x)>=0);}
    point turn90(){return point(-y,x);}  
    point unit(){db w=abs(); return point(x/w,y/w);}
};
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;}
int comp(point k1,point k2){
    if(k1.getP()==k2.getP())return sign(cross(k1,k2))>0;
    return k1.getP()<k2.getP();
}

struct line{
    point p[2];
    line(point k1,point k2){p[0]=k1; p[1]=k2;}
    point& operator [] (int k){return p[k];}
    int include(point k){return sign(cross(p[1]-p[0],k-p[0]))>0;}//k在l左端 
    point dir(){return p[1]-p[0];}
    line push(db eps){//向左边平移eps 
        point delta = (p[1]-p[0]).turn90().unit()*eps;
        return line(p[0]+delta,p[1]+delta); 
    }
};

//输入的点是顺时针:ans<0,逆时针:ans>0 
bool judge(vector<point> v){
    double ans=0;
    for(int i=1;i<v.size()-1;i++)
        ans+=cross(v[i]-v[0],v[i+1]-v[0]);
    return ans>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);
}
point getLL(line k1,line k2){return getLL(k1[0],k1[1],k2[0],k2[1]);}
int parallel(line k1,line k2){return sign(cross(k1.dir(),k2.dir()))==0;}
int sameDir(line k1,line k2){return parallel(k1,k2)&&sign(dot(k1.dir(),k2.dir()))==1;}
int checkpos(line k1,line k2,line k3){
    point p=getLL(k1,k2);
    if(sign(cross(k3[1]-k3[0],p-k3[0]))>0)return 1;
    return 0;
}//k1,k2交点在 k3 左端 
int operator<(line k1,line k2){//按极角排序,角度相同的从左到右排 
    if(sameDir(k1,k2))return k2.include(k1[0]);
    return comp(k1.dir(),k2.dir());
} 
vector<line> getHL(vector<line> L,int flag){ // 求半平面交 , 半平面是逆时针方向 , 输出按照逆时针
    sort(L.begin(),L.end()); deque<line> q;
    /*
    if(flag){
        for(line l:L)cout<<l[0].x<<" "<<l[0].y<<" "<<l[1].x<<" "<<l[1].y<<'
';
    }*/
    
    for (int i=0;i<(int)L.size();i++){
        if (i&&sameDir(L[i],L[i-1])) continue;
        while (q.size()>1&&!checkpos(q[q.size()-2],q[q.size()-1],L[i])) q.pop_back();
        while (q.size()>1&&!checkpos(q[1],q[0],L[i])) q.pop_front();
        q.push_back(L[i]);
    }
    while (q.size()>2&&!checkpos(q[q.size()-2],q[q.size()-1],q[0])) q.pop_back();
    while (q.size()>2&&!checkpos(q[1],q[0],q[q.size()-1])) q.pop_front();
    vector<line>ans; for (int i=0;i<q.size();i++) ans.push_back(q[i]);
    return ans;
}

vector<point>v;
vector<line>L;
int n;
db A[N],B[N],C[N];

int solve(int id){
    L.clear();//加一个边框 
    L.push_back(line(point(0,0),point(inf,0)));
    L.push_back(line(point(inf,0),point(inf,inf)));
    L.push_back(line(point(inf,inf),point(0,inf)));
    L.push_back(line(point(0,inf),point(0,0)));
    for(int i=0;i<n;i++){        
        if(i==id)continue;
        //ax+by+c>0 的方程组通过半平面交求解 
        db a=1.0/A[i]-1.0/A[id];
        db b=1.0/B[i]-1.0/B[id];
        db c=1.0/C[i]-1.0/C[id];
        point k1,k2;    
        if(sign(a)==0){//by+c>0,
            if(sign(b)==0 && sign(c)<=0)return 0;
            else if(sign(b)==0 && sign(c)>0)continue;
            k1.x=0;k2.x=sign(b);
            k1.y=k2.y=-c/b;
        }
        else {
            if(sign(b)==0){//ax+c>0
                k1.y=0,k2.y=-sign(a);
                k1.x=k2.x=-c/a;
            }
            else {//ax+by+c>0
                k1.x=0,k1.y=-c/b;
                k2.x=sign(b),k2.y=-(c+a*sign(b))/b;
            }
        }
        L.push_back(line(k1,k2));
    } 
    /*
    if(id==2){
        for(line l:L)cout<<l[0].x<<" "<<l[0].y<<" "<<l[1].x<<" "<<l[1].y<<'
';
    }*/
    int flag=0;
    if(id==1)flag=1;
    vector<line>res=getHL(L,flag);//cout<<res.size()<<" ";
    /*for(auto l:res)
        cout<<l[0].x<<" "<<l[0].y<<" "<<l[1].x<<" "<<l[1].y<<'
';
    */if(res.size()>=3)return 1;
    return 0;
}

int main(){
    cin>>n;
    for(int i=0;i<n;i++)cin>>A[i]>>B[i]>>C[i];
    for(int i=0;i<n;i++)
        if(solve(i))puts("Yes");
        else puts("No");
}

/*
13
1020 1090 1080
1000 1080 1100
1000 1090 1100
1010 1010 1090
1090 1080 1010
1060 1070 1040

1080 1050 1020
1040 1010 1060
1090 1000 1010
1070 1010 1030
1060 1010 1040
1070 1080 1030

1040 1070 1060

100
1020 1090 1080
1000 1080 1100
1000 1090 1100
1010 1010 1090
1090 1080 1010
1060 1070 1040

1080 1050 1020
1040 1010 1060
1090 1000 1010
1070 1010 1030
1060 1010 1040

1070 1080 1030
1040 1070 1060
1020 1000 1080
1080 1070 1020
1040 1000 1060
1040 1060 1060
1030 1080 1070
1050 1020 1050
1030 1010 1070
1020 1060 1080
1010 1060 1090
1050 1030 1050
1060 1040 1040
1090 1030 1010
1050 1080 1050
1020 1050 1080
1070 1050 1030
1030 1050 1070
1010 1020 1090
1040 1050 1060
1080 1080 1020
1020 1020 1080
1000 1050 1100
1000 1020 1100
1070 1030 1030
1070 1040 1030
1020 1070 1080
1020 1080 1080
1080 1090 1020
1050 1070 1050
1040 1040 1060
1080 1040 1020
1050 1040 1050
1080 1020 1020
1030 1040 1070
1090 1040 1010
1020 1030 1080
1080 1060 1020
1070 1020 1030
1060 1030 1040
1000 1040 1100
1060 1080 1040
1010 1040 1090
1090 1090 1010
1090 1060 1010
1000 1060 1100
1030 1090 1070
1070 1060 1030
1080 1000 1020
1010 1000 1090
1050 1060 1050
1090 1070 1010
1010 1030 1090
1010 1080 1090
1010 1050 1090
1000 1070 1100
1010 1070 1090
1000 1010 1100
1030 1030 1070
1060 1090 1040
1090 1050 1010
1080 1010 1020
1010 1090 1090
1070 1090 1030
1020 1010 1080
1030 1020 1070
1060 1050 1040
1060 1060 1040
1050 1050 1050
1050 1090 1050
1040 1090 1060
1000 1030 1100
1070 1070 1030
1040 1020 1060
1050 1000 1050
1030 1070 1070
1060 1000 1040
1020 1040 1080
1070 1000 1030
1080 1030 1020
1040 1030 1060
1050 1010 1050
1090 1020 1010
1030 1060 1070
1060 1020 1040
1090 1010 1010
1040 1080 1060
1030 1000 1070
1000 1000 1100

*/
原文地址:https://www.cnblogs.com/zsben991126/p/12378553.html