zoukankan      html  css  js  c++  java
  • [bzoj3630][JLOI2014]镜面通道_计算几何_网络流_最小割

    镜面通道 bzoj-3630 JLOI-2014

    题目大意题目链接

    注释:略。


    想法

    我们发现,只要上下界没有被完全封死,我们就一定有一条合法的光路。

    所以只需要将上界和下界拆开即可。

    拆点,把每个点分为入点和出点,入点向出点连1的边。

    元件之间如果连通就连$inf$。

    和上界连通就对源点连$inf$,和下界连通就和汇点连$inf$。

    最后求最小割即为答案。

    Code

    // luogu-judger-enable-o2
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define N 303
    #define M 370000
    #define inf 0x7fffffff
    #define ll long long
    using namespace std;
    int to[M],hd[M],lk[N<<1],len[M],cnt=1,T;
    void add(int u,int v,int w)
    {
        to[++cnt]=v,hd[cnt]=lk[u],len[cnt]=w,lk[u]=cnt;
        to[++cnt]=u,hd[cnt]=lk[v],lk[v]=cnt;
    }
    struct pt
    {
        ll x,y;
        void read()
        {scanf("%lld%lld",&x,&y);}
    }tp1,tp2;
    inline ll Dis(pt a,pt b)
    {return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);}
    struct cir
    {pt o;int r;}Cir[N];
    struct rec
    {pt x1,x2;}Rec[N],ss,tt;
    short n,loc[N];
    int X,Y,ans;
    ll d,xx,yy;
    bool judge(cir a,rec b)
    {
        d=a.r,xx=a.o.x,yy=a.o.y;
        if(xx>=b.x1.x-d&&xx<=b.x2.x+d&&yy>=b.x1.y&&yy<=b.x2.y
        ||xx>=b.x1.x&&xx<=b.x2.x&&yy>=b.x1.y-d&&yy<=b.x2.y+d)return 1;
        tp1.x=b.x1.x,tp2.y=b.x2.y,tp2.x=b.x2.x,tp2.y=b.x1.y;d*=d;
        return Dis(a.o,tp1)<=d||Dis(a.o,tp2)<=d||Dis(a.o,b.x1)<=d||Dis(a.o,b.x2)<=d;
    }
    bool check(int a,int b)
    {
        if(loc[a]>loc[b])swap(a,b);
        if(loc[b]<2)return((Cir[a].r+Cir[b].r)*(Cir[a].r+Cir[b].r)>=Dis(Cir[a].o,Cir[b].o));
        if(loc[a]>1)return (Rec[a].x1.x<=Rec[b].x1.x&&Rec[b].x1.x<=Rec[a].x2.x||
        Rec[a].x1.x<=Rec[b].x2.x&&Rec[b].x2.x<=Rec[a].x2.x)&&
        (Rec[a].x1.y<=Rec[b].x1.y&&Rec[b].x1.y<=Rec[a].x2.y||
        Rec[a].x1.y<=Rec[b].x2.y&&Rec[b].x2.y<=Rec[a].x2.y);
        return judge(Cir[a],Rec[b]);
    }
    int k,q[N<<1],h,t,dis[N<<1],cur[N<<1];
    bool bfs()
    {
        for(int i=0;i<=T;i++)
        dis[i]=0,cur[i]=lk[i];
        h=0,t=dis[0]=1;
        while(h<t)
        {
            k=q[h++];
            for(int i=lk[k];i;i=hd[i])
            if(len[i]&&!dis[to[i]])
            dis[q[t++]=to[i]]=dis[k]+1;
        }
        return dis[T];
    }
    int dfs(int x,int f)
    {
        if(x==T||!f)return f;
        int r=0,cst;
        for(int &i=cur[x];i;i=hd[i])
        if(dis[to[i]]==dis[x]+1)
        {
            cst=dfs(to[i],f<len[i]?f:len[i]);
            f-=cst,len[i]-=cst;
            r+=cst,len[i^1]+=cst;
            if(!f)break;
        }
        if(!r)dis[x]=0;
        return r;
    }
    int main()
    {
        scanf("%d%d",&X,&Y);
        ss={{0,0},{X,0}};tt={{0,Y},{X,Y}};
        scanf("%d",&n);T=n<<1|1;
        for(int i=1;i<=n;i++)
        {
            add(i,i+n,1);
            scanf("%d",loc+i);
            if(loc[i]<2)
            {
                Cir[i].o.read(),scanf("%lld",&Cir[i].r);
                if(judge(Cir[i],ss))add(0,i,inf);
                if(judge(Cir[i],tt))add(i+n,T,inf);
            }
            else
            {
                Rec[i].x1.read(),Rec[i].x2.read();
                if(Rec[i].x1.y<=0&&Rec[i].x1.x<=X&&Rec[i].x2.x>=0)add(0,i,inf);
                if(Rec[i].x2.y>=Y&&Rec[i].x1.x<=X&&Rec[i].x2.x>=0)add(i+n,T,inf);
            }
            for(int j=1;j<i;j++)
            if(check(j,i))
            add(j+n,i,inf),add(i+n,j,inf);
        }
        while(bfs())ans+=dfs(0,inf);
        printf("%d",ans);
    }
    

    小结:好题好题。就是特判有点恶心。

  • 相关阅读:
    Linux内核从原理到代码详解
    linux内核研究-8-块设备I/O层
    《Linux内核分析》课程总结
    Nginx 重写规则指南1
    Nginx初探
    Nginx源码分析:3张图看懂启动及进程工作原理
    nginx源码分析 +redis的那些事儿
    I/O 模型及其设计模式
    高并发性能调试经验分享
    myawr
  • 原文地址:https://www.cnblogs.com/ShuraK/p/10244430.html
Copyright © 2011-2022 走看看