BZOJ3630

来源:互联网 发布:网络缓存级别 影音先锋 编辑:程序博客网 时间:2024/06/01 09:32

3630: [JLOI2014]镜面通道

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 478  Solved: 166
[Submit][Status][Discuss]

Description

在一个二维平面上,有一个镜面通道,由镜面AC,BD组成,AC,BD长度相等,且都平行于x轴,B位于(0,0)。通道中有n个外表面为镜面的光学元件,光学元件α为圆形,光学元件β为矩形(这些元件可以与其他元件和通道有交集,具体看下图)。光线可以在AB上任一点以任意角度射入通道,光线不会发生削弱。当出现元件与元件,元件和通道刚好接触的情况视为光线无法透过(比如两圆相切)。现在给出通道中所有元件的信息(α元件包括圆心坐标和半径xi,yi,ri,β元件包括左下角和右上角坐标x1,y1,x2,y2)

如上图,S到T便是一条合法线路。

当然,显然存在光线无法透过的情况,现在交给你一个艰巨的任务,请求出至少拿走多少个光学元件后,存在一条光线线路可以从CD射出。

下面举例说明:

现在假设,取走中间那个矩形,那么就可以构造出一条穿过通道的光路,如图中的S到T。

Input

第一行包含两个整数,x,y,表示C点坐标

第二行包含一个数字,n,表示有n个光学元件

接下来n行

第一个数字如果是1,表示元件α,后面会有三个整数xi,yi,ri分别表示圆心坐标和半径

第一个数字如果是2,表示元件β,后面会有四个整数x1,y1,x2,y2分别表示左下角和右上角坐标(矩形都平行,垂直于坐标轴)

Output

 

输出包含一行,至少需要拿走的光学元件个数m

Sample Input

1000 100

6

1 500 0 50

2 10 10 20 100

2 100 10 200 100

2 300 10 400 100

2 500 10 600 100

2 700 0 800 100

Sample Output

2

HINT

x<=100000,y<=1000,n<=300


 

Source


这个题啊,Excited!网络流最小割嘛,把每个图形拆点,即第i个图形向第i+n个图形连流量为1的无向边

如果一个图形与另一个图形相交,就连流量为INF的无向边

判相交的话,就是矩形与圆相交,搞一个计算几何求点到线段距离就好了

PS:与边界相交可以把边界视为矩形搞。


#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<cmath>#define maxn 910#define maxm 300100#define pf(x) (1ll*(x)*(x))using namespace std;int n,bg,ed,head[maxn],dep[maxn],q[maxn],ql,qr,esz=2;long long x,y;struct edge{    int r,nxt,w;}e[maxm];struct Vector{    double x,y;    Vector(){}    Vector(double x,double y):x(x),y(y){}    Vector operator-(const Vector& vec)const{        return Vector(x-vec.x,y-vec.y);    }};double cross(const Vector& a,const Vector& b){    return a.x*b.y-a.y*b.x;}double dot(const Vector& a,const Vector& b){    return a.x*b.x+a.y*b.y;}double length(const Vector& a){    return sqrt((double)dot(a,a));}double distoseg(const Vector x,const Vector a,const Vector b){    Vector v1=b-a,v2=x-a,v3=x-b;    if(dot(v1,v2)<0)return length(v2);    if(dot(v1,v3)>0)return length(v3);    return ((double)abs(cross(v1,v2)))/length(v1);}int dcmp(double a){    return fabs(a)<1e-7?0:(a>0?1:-1);}struct data{    long long x1,y1,x2,y2,att;    void circle(long long x,long long y,long long r){        x1=x;y1=y;x2=r;att=1;    }    void square(long long x1,long long y1,long long x2,long long y2){        this->x1=x1;this->x2=x2;        this->y1=y1;this->y2=y2;        att=2;    }}d[maxn];void addedge(int u,int v,int w){//    printf("[%d,%d]\n",u,v);    e[esz].r=v;e[esz].nxt=head[u];    e[esz].w=w;head[u]=esz++;    e[esz].r=u;e[esz].nxt=head[v];    e[esz].w=0;head[v]=esz++;}bool isincir(long long x1,long long y1,data& d){    return pf(x1-d.x1)+pf(y1-d.y1)<=pf(d.x2);}bool isinsq(long long x1,long long y1,data& d){    return d.x1<=x1&&x1<=d.x2&&d.y1<=y1&&y1<=d.y2;}bool cirandcir(data& x,data& y){    return pf(x.x1-y.x1)+pf(x.y1-y.y1)<=pf(x.x2+y.x2);}bool pd(long long x1,long long y1,long long x2,long long y2,long long x,long long y,long long r){    return dcmp(distoseg(Vector(x,y),Vector(x1,y1),Vector(x2,y2))-r)<=0;}bool bfs(){    ql=qr=0;    q[qr++]=bg;    memset(dep,0,sizeof(dep));    dep[bg]=1;    while(ql<qr){        int x=q[ql++];        for(int t=head[x];t;t=e[t].nxt)if(!dep[e[t].r]&&e[t].w)            dep[e[t].r]=dep[x]+1,q[qr++]=e[t].r;    }    return dep[ed]!=0;}int find(int u,int flow){    if(u==ed)return flow;    int a=0,used=0;    for(int t=head[u];t;t=e[t].nxt)if(e[t].w&&dep[e[t].r]==dep[u]+1&&(a=find(e[t].r,min(flow,e[t].w)))){        e[t].w-=a;e[t^1].w+=a;        used+=a;        if(used==flow)return used;             }    if(!used)dep[u]=0;    return used;}bool check(int i,int j){    if(d[i].att==1&&d[j].att==1){        if(cirandcir(d[i],d[j])||cirandcir(d[i],d[j]))            return true;    } else if(d[i].att==2&&d[j].att==2){        if(isinsq(d[i].x1,d[i].y1,d[j])||isinsq(d[i].x2,d[i].y1,d[j])            ||isinsq(d[i].x1,d[i].y2,d[j])||isinsq(d[i].x2,d[i].y2,d[j])||            isinsq(d[j].x1,d[j].y1,d[i])||isinsq(d[j].x2,d[j].y1,d[i])            ||isinsq(d[j].x1,d[j].y2,d[i])||isinsq(d[j].x2,d[j].y2,d[i]))                        return true;    } else {        int ni=i,nj=j;        if(d[ni].att==2&&d[nj].att==1)swap(ni,nj);        if(pd(d[nj].x1,d[nj].y1,d[nj].x1,d[nj].y2,d[ni].x1,d[ni].y1,d[ni].x2))return true;        else if(pd(d[nj].x1,d[nj].y2,d[nj].x2,d[nj].y2,d[ni].x1,d[ni].y1,d[ni].x2))return true;        else if(pd(d[nj].x2,d[nj].y2,d[nj].x2,d[nj].y1,d[ni].x1,d[ni].y1,d[ni].x2))return true;        else if(pd(d[nj].x2,d[nj].y1,d[nj].x1,d[nj].y1,d[ni].x1,d[ni].y1,d[ni].x2))return true;    }    return false;}int main(){    scanf("%lld%lld%d",&x,&y,&n);    for(int i=1;i<=n;++i){        int op;scanf("%d",&op);        if(op==1){            long long x,y,r;scanf("%lld%lld%lld",&x,&y,&r);            d[i].circle(x,y,r);        } else {            long long  x1,y1,x2,y2;            scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);            d[i].square(x1,y1,x2,y2);        }    }    d[n+1].square(0,y,x,1ll<<60);    d[n+2].square(0,-1ll<<60,1ll<<60,0);    for(int i=1;i<=n;++i)addedge(i,i+n,1),addedge(i+n,i,1);    for(int i=1;i<=n;++i)        for(int j=i+1;j<=n;++j)            if(check(i,j)) addedge(i+n,j,1<<30),addedge(j+n,i,1<<30);bg=0,ed=n*2+1;    for(int i=1;i<=n;++i)if(check(n+1,i))addedge(i+n,ed,1<<30);    for(int i=1;i<=n;++i)if(check(n+2,i))addedge(bg,i,1<<30);    int ans=0,f=0;    while(bfs())while(f=find(bg,1<<30))ans+=f;    printf("%d",ans);    }











0 0
原创粉丝点击