bzoj 3630 [JLOI2014]镜面通道 计算几何 网络流

只要上下边界不连通就可以。
然后两个图形相交就连边,拆点跑网络流就行了。
判相交比较麻烦(抑或是我写得麻烦)

#include <bits/stdc++.h>
using namespace std;
#define N 310
#define inf 1e9
#define eps 1e-8
#define M 1100000
int n,X,Y,c1,c2,cnt,S,T,tot,ans;
int pos[N][2],head[N<<1],nex[M],to[M],val[M],deep[N<<1];
queue<int>q;
void add(int x,int y,int v)
{
    tot++;
    nex[tot]=head[x];head[x]=tot;
    to[tot]=y;val[tot]=v;
}
void ade(int x,int y,int v)
{add(x,y,v);add(y,x,0);}
void ad(int x,int y)
{
    ade(pos[x][1],pos[y][0],inf);
    ade(pos[y][1],pos[x][0],inf);
}
struct poi
{
    double x,y;
    poi(){}
    poi(double x,double y):x(x),y(y){}
    friend poi operator - (const poi &r1,const poi &r2)
    {return poi(r1.x-r2.x,r1.y-r2.y);}
    friend poi operator + (const poi &r1,const poi &r2)
    {return poi(r1.x+r2.x,r1.y+r2.y);}
    friend bool operator == (const poi &r1,const poi &r2)
    {return fabs(r1.x-r2.x)<eps&&fabs(r1.y-r2.y)<eps;}
    friend poi operator * (double x,const poi &r1)
    {return poi(x*r1.x,x*r1.y);}
    friend double operator * (const poi &r1,const poi &r2)
    {return r1.x*r2.x+r1.y*r2.y;}
    friend double operator ^ (const poi &r1,const poi &r2)
    {return r1.x*r2.y-r2.x*r1.y;}
};
struct line
{
    poi p,v;
    line(){}
    line(poi p,poi v):p(p),v(v){}
};
struct circle
{
    poi p;double r;int num;
    void read()
    {
        scanf("%lf%lf%lf",&p.x,&p.y,&r);
        if(p.y<=r+eps)ade(S,pos[num][0],inf);
        if(p.y+r+eps>=Y)ade(pos[num][1],T,inf);
    }
}a[N];
struct polygon
{
    poi p[6];int num;
    void read()
    {
        scanf("%lf%lf%lf%lf",&p[2].x,&p[2].y,&p[4].x,&p[4].y);
        p[1]=poi(p[2].x,p[4].y);
        p[3]=poi(p[4].x,p[2].y);
        if(p[2].y<=eps)ade(S,pos[num][0],inf);
        if(p[1].y+eps>=Y)ade(pos[num][1],T,inf);
        p[5]=p[1];
    }
    int ins(poi p1)
    {return p1.x>p[1].x&&p1.x<p[4].x&&p1.y>p[2].y&&p1.y<p[1].y;}
}b[N];
poi intersect(line l1,line l2)
{
    poi u=l1.p-l2.p;
    double tmp=(u^l2.v)/(l2.v^l1.v);
    return l1.p+tmp*l1.v;
}
double dis(poi p1,poi p2)
{return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));}
int check(circle c1,poi p1,poi p2)
{
    line l1=line(p1,p1-p2);
    poi p=intersect(l1,line(c1.p,poi(-l1.v.y,l1.v.x)));
    if(dis(c1.p,p)>c1.r+eps)return 0;
    if(p==c1.p&&(p-p1)*(p-p2)>eps)return 0;
    if((((c1.p-p1)^(c1.p-p))<0)^(((c1.p-p)^(c1.p-p2))<0))
        return 0;
    return 1;
}
int intersect(circle c1,circle c2)
{return dis(c1.p,c2.p)<c1.r+c2.r+eps;}
int intersect(polygon p1,polygon p2)
{
    if(p1.p[1].x>p2.p[4].x||p2.p[1].x>p1.p[4].x)return 0;
    if(p1.p[1].y<p2.p[2].y||p2.p[1].y<p1.p[2].y)return 0;
    return 1;
}
int intersect(circle c1,polygon p1)
{
    if(p1.ins(c1.p))return 1;
    for(int i=1;i<=4;i++)
        if(dis(c1.p,p1.p[i])<c1.r+eps)return 1;
    for(int i=1;i<=4;i++)
        if(check(c1,p1.p[i],p1.p[i+1]))
            return 1;
    return 0;
}
int dfs(int x,int mv)
{
    if(x==T)return mv;
    int tmp=0;
    for(int i=head[x];i;i=nex[i])
        if(val[i]&&deep[to[i]]==deep[x]+1)
        {
            int t=dfs(to[i],min(mv-tmp,val[i]));
            if(!t)deep[to[i]]=-1;
            tmp+=t;
            val[i]-=t;val[i^1]+=t;
            if(tmp==mv)break;
        }
    return tmp;
}
int bfs()
{
    while(!q.empty())q.pop();
    memset(deep,-1,sizeof(deep));
    q.push(S);deep[S]=0;
    while(!q.empty())
    {
        int t=q.front();q.pop();
        for(int i=head[t];i;i=nex[i])
            if(val[i]&&deep[to[i]]==-1)
            {
                deep[to[i]]=deep[t]+1;
                q.push(to[i]);
                if(to[i]==T)return 1;
            }
    }
    return 0;
}
int main()
{
    tot=1;
    scanf("%d%d%d",&X,&Y,&n);
    for(int i=1;i<=n;i++)
    {
        pos[i][0]=++cnt,pos[i][1]=++cnt;
        ade(pos[i][0],pos[i][1],1);
    }
    S=++cnt;T=++cnt;
    for(int i=1,tp;i<=n;i++)
    {
        scanf("%d",&tp);
        if(tp==1)
            {a[++c1].num=i;a[c1].read();}
        else{b[++c2].num=i;b[c2].read();}
    }
    for(int i=1;i<=c1;i++)
        for(int j=i+1;j<=c1;j++)
            if(intersect(a[i],a[j]))
                ad(a[i].num,a[j].num);

    for(int i=1;i<=c2;i++)
        for(int j=i+1;j<=c2;j++)
            if(intersect(b[i],b[j]))
                ad(b[i].num,b[j].num);

    for(int i=1;i<=c1;i++)
        for(int j=1;j<=c2;j++)
            if(intersect(a[i],b[j]))
                ad(a[i].num,b[j].num);

    while(bfs())
        ans+=dfs(S,inf);
    printf("%d\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值