【幾何剖分 + 掃描線】HDU - 4629 - Burning

題目鏈接http://acm.hdu.edu.cn/showproblem.php?pid=4629


題意

給出n(n<=50)n(n<=50)個三角形,問被覆蓋ii次的面積是多少(1<=i<=n)(1<=i<=n)


題解

以所有三角形線段兩兩交點的x座標爲分界線,把圖形分成若干個小區間,每個區間只包含若干個梯形,然後對於每個區間按照y座標掃描過去,累加一下答案即可。


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const int N=1e6+7;
const db eps=1e-8;
int t,n,tx,ts;
db X1,X2;
int sign(db k){if(k>eps) return 1;if(k<-eps) return -1;return 0;}
int dcmp(db k1,db k2){return sign(k1-k2);}
int inmid(db k1,db k2,db k3){return sign(k1-k3)*sign(k2-k3)<=0;}
struct Point{
    db x,y;
    Point operator - (const Point k)const{return (Point){x-k.x,y-k.y};}
    Point operator + (const Point k)const{return (Point){x+k.x,y+k.y};}
    Point operator * (const db k)const{return (Point){x*k,y*k};}
    Point operator / (const db k)const{return (Point){x/k,y/k};}
    void input(){scanf("%lf%lf",&x,&y);}
};
db cross(Point k1,Point k2){return k1.x*k2.y-k1.y*k2.x;}
struct Seg{
    Point s,e;
    int id;
    bool ck(){return inmid(s.x,e.x,X1)&&inmid(s.x,e.x,X2);}
    db gety(db x){return (e.y-s.y)*(x-s.x)/(e.x-s.x)+s.y;}
    db gety1(){return gety(X1);}
    db gety2(){return gety(X2);}
    bool operator < (Seg k){
        if(dcmp(gety1(),k.gety1())==0) return gety2()<k.gety2();
        return gety1()<k.gety1();
    }
    void output(){printf("(%f,%f) - (%f,%f)\n",s.x,s.y,e.x,e.y);}
}s[N],ns[N];
struct Triangle{
    Point p[3];
}a[60];
int intersect(db l1,db r1,db l2,db r2){
    if (l1>r1) swap(l1,r1); if (l2>r2) swap(l2,r2); return dcmp(r1,l2)!=-1&&dcmp(r2,l1)!=-1;
}
int checkSS(Point k1,Point k2,Point k3,Point k4){
    return intersect(k1.x,k2.x,k3.x,k4.x)&&intersect(k1.y,k2.y,k3.y,k4.y)&&
    sign(cross(k3-k1,k4-k1))*sign(cross(k3-k2,k4-k2))<=0&&
    sign(cross(k1-k3,k2-k3))*sign(cross(k1-k4,k2-k4))<=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 xx[N];
db ans[N];
bool vis[N];
int main()
{
    scanf("%d",&t);
    while(t--){
        tx=ts=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            ans[i]=0;
            for(int j=0;j<3;j++){
                a[i].p[j].input();
            }
        }
        for(int i=1;i<=n;i++){
            for(int u=0,uu=1;u<3;u++,uu=(uu+1)%3){
                s[++ts]=(Seg){a[i].p[u],a[i].p[uu],i};
                if(s[ts].s.x>s[ts].e.x) swap(s[ts].s,s[ts].e);
            }
        }
        for(int i=1;i<=ts;i++){
            for(int j=i+1;j<=ts;j++){
                if(cross(s[i].s-s[j].s,s[i].s-s[j].e)==0&&cross(s[i].e-s[j].s,s[i].e-s[j].e)==0) continue;
                if(checkSS(s[i].s,s[i].e,s[j].s,s[j].e)){
                    xx[++tx]=getLL(s[i].s,s[i].e,s[j].s,s[j].e).x;
                }
            }
        }
        sort(xx+1,xx+1+tx);
        int nt=1;
        for(int i=2;i<=tx;i++){
            if(dcmp(xx[i],xx[i-1])>0) xx[++nt]=xx[i];
        }
        tx=nt;
        for(int i=1,j=2;j<=tx;i++,j++){
            X1=xx[i],X2=xx[j],ts=0;
            for(int j=1;j<=n*3;j++){
                if(s[j].ck()) ns[++ts]=s[j];
                vis[s[j].id]=0;
            }
            sort(ns+1,ns+1+ts);
            int sum=0;
            for(int u=1,v=2;v<=ts;u++,v++){
                if(vis[ns[u].id]==false) vis[ns[u].id]=true,sum++;
                else sum--;
                ans[sum]+=(ns[v].gety1()-ns[u].gety1()+ns[v].gety2()-ns[u].gety2())*(xx[j]-xx[i])/2;
            }
        }
        for(int i=1;i<=n;i++){
            printf("%.10f\n",ans[i]);
        }
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章