zoukankan      html  css  js  c++  java
  • bzoj2965: 保护古迹

    Description

      某校由于历史悠久,校园中有大量的名胜古迹。为了更好地保护这些古迹,学校决定用篱笆将这些古迹围起来。
      现在已知有p个地点的古迹需要保护。这些古迹可以看做二维平面上的整数点。有n个点可以作为篱笆的端点,这些端点的坐标也为二维平面上的整数。端点用1到n的整数编号。
      有m对端点之间可以修建篱笆。用(u,v,w)描述一段可以修建的篱笆,表示端点u和端点v之间可以花费w的代价修建一段。篱笆都看做直线段。为了方便设计,这些可以修建的篱笆都是不会相交的(只会在端点处相交)。
      将一个古迹围起来是指存在一个由篱笆构成的简单多边形,这个古迹在该多边形内部。
      由于经费问题,学校希望修建篱笆的花费最小。你需要输出将至少1个,2个,…,p个古迹围起来的最小花费。

    Input

      第一行包含三个正整数p,n,m表示古迹的个数,端点个数和可以修建的篱笆条数。
      接下来p行,每行包含两个整数,表示每个古迹的坐标。
      接下来n行,每行包含两个整数,表示每个端点的坐标。这些端点按照输入的顺序依次用1到n的整数编号。
      最后m行,每行包含三个非负整数u,v,w,表示可以在端点u和端点v之间花w的代价修建一段篱笆。

    Output

      输出p行,分别表示将至少1个,2个,…,p个古迹围起来的最小花费。

    扫描线做一下平面图转对偶图以及点定位,然后枚举选哪些点求最小割。
    #include<bits/stdc++.h>
    typedef long long i64;
    int p,n,m,f[30007],ep=0;
    int gf(int x){
        while(x!=f[x])x=f[x]=x[f][f];
        return x;
    }
    void mg(int a,int b){
        f[gf(a)]=gf(b);
    }
    struct pos{
        int x,y;
        void R(){scanf("%d%d",&x,&y);}
        pos operator+(pos w)const{return (pos){x+w.x,y+w.y};}
        pos operator-(pos w)const{return (pos){x-w.x,y-w.y};}
        i64 operator*(pos w)const{return i64(x)*w.y-i64(y)*w.x;}
    }ps[15];
    struct edge{
        int to,v;
        double a;
        pos p;
        int i1,i2;
        bool operator<(const edge&e)const{
            return fabs(a-e.a)<0.5?p*e.p>0:a<e.a;
        }
    };
    int min(int a,int b){return a<b?a:b;}
    int max(int a,int b){return a>b?a:b;}
    struct seg{
        pos p1,p2;
        int i1,i2;
        double at(double x)const{
            int d=p2.x-p1.x;
            return d?((x-p1.x)*p2.y+(p2.x-x)*p1.y)/d:p1.y;
        }
        bool operator<(const seg&w)const{
            double x1=(max(p1.x,w.p1.x)+min(p2.x,w.p2.x))*.5;
            return at(x1)<w.at(x1);
        }
    };
    struct event{
        int tp,x,id1,id2;
        bool operator<(const event&e)const{return x<e.x||x==e.x&&tp<e.tp;}
        void cal();
    }ev[50007];
    int evp=0;
    struct vertex{
        pos p;
        std::vector<edge>e;
        void R(){p.R();}
        void ae(int,int,int,int);
        void init();
        seg getseg(int w){
            return (seg){p,e[w].p+p,e[w].i1,e[w].i2};
        }
    }ns[111];
    void vertex::ae(int to,int v,int id1,int id2){
        pos d=ns[to].p-p;
        e.push_back((edge){to,v,atan2(d.y,d.x),d,id1,id2});
    }
    void vertex::init(){
        edge*es=e.data();
        int ec=e.size();
        if(ec){
            std::sort(es,es+ec);
            for(int i=1;i<ec;++i)mg(es[i-1].i2,es[i].i1);
            mg(es[ec-1].i2,es[0].i1);
            for(int i=0;i<ec;++i)if(es[i].p.x>0){
                ev[evp++]=(event){1,p.x,this-ns,i};
                ev[evp++]=(event){-1,p.x+es[i].p.x,this-ns,i};
            }
        }
    }
    std::set<seg>ln;
    std::set<seg>::iterator it,il,ir,its[50007];
    int itp=0;
    void event::cal(){
        if(tp==-1){
            seg s=ns[id1].getseg(id2);
            ln.erase(ln.find(s));
        }else if(tp==2){
            it=ln.lower_bound((seg){ps[id1],ps[id1]});
            mg(id1+1,it!=ln.end()?it->i1:0);
            mg(it!=ln.begin()?(--it)->i2:0,id1+1);
        }else{
            seg s=ns[id1].getseg(id2);
            its[itp++]=ln.insert(s).first;
        }
    }
    int id[50007],idp=0,ans[15];
    namespace mxf{
    const int N=300007,inf=0x3f3f3f3f;
    struct edge{
        int to,nx,v;
    }e[N];
    int e0[N],ep=2,h[N],q[N],S,T;
    void ae(int a,int b,int c,int c2){
        if(!a||!b||a==b||c+c2==0)return;
        e[ep]=(edge){b,e0[a],c};e0[a]=ep++;
        e[ep]=(edge){a,e0[b],c2};e0[b]=ep++;
    }
    int min(int a,int b){return a<b?a:b;}
    bool bfs(){
        for(int i=1;i<=idp;++i)h[i]=0;
        int ql=0,qr=0;
        h[q[++qr]=S]=1;
        while(ql!=qr){
            int w=q[++ql];
            if(w==T)return 1;
            for(int i=e0[w];i;i=e[i].nx)if(e[i].v){
                int u=e[i].to;
                if(!h[u])h[q[++qr]=u]=h[w]+1;
            }
        }
        return 0;
    }
    int dfs(int w,int f){
        if(w==T)return f;
        int c,used=0;
        for(int i=e0[w];i;i=e[i].nx)if(e[i].v){
            int u=e[i].to;
            if(h[u]!=h[w]+1)continue;
            c=dfs(u,min(e[i].v,f-used));
            e[i].v-=c,e[i^1].v+=c,used+=c;
            if(f==used)return f;
        }
        h[w]=0;
        return used;
    }
    void cal(int s){
        ep=2;
        S=idp+1;T=id[gf(0)];
        int c1=0;
        for(int i=1;i<=S;++i)e0[i]=0;
        for(int i=0;i<p;++i)if(s>>i&1){
            ++c1;
            ae(S,id[gf(i+1)],inf,0);
        }
        for(int i=1;i<=n;++i){
            for(int j=0;j<ns[i].e.size();++j){
                ::edge&e=ns[i].e[j];
                if(e.p.x>0||e.p.x==0&&e.p.y>0)ae(id[gf(e.i1)],id[gf(e.i2)],e.v,e.v);
            }
        }
        int f=0;
        while(bfs()){
            f+=dfs(S,inf);
            if(f>=ans[c1])return;
        }
        ans[c1]=f;
    }
    }
    int main(){
        scanf("%d%d%d",&p,&n,&m);
        for(int i=0;i<p;++i)ps[i].R(),ev[evp++]=(event){2,ps[i].x,i};
        for(int i=1;i<=n;++i)ns[i].R();
        ep=p;
        for(int i=0,a,b,c;i<m;++i){
            scanf("%d%d%d",&a,&b,&c);
            ep+=2;
            ns[a].ae(b,c,ep-1,ep);
            ns[b].ae(a,c,ep,ep-1);
        }
        for(int i=1;i<=ep;++i)f[i]=i;
        for(int i=1;i<=n;++i)ns[i].init();
        std::sort(ev,ev+evp);
        for(int i=0,j=0;i<evp;i=j){
            for(;j<evp&&ev[i].x==ev[j].x;ev[j++].cal());
            while(itp){
                il=ir=it=its[--itp];
                mg(it->i2,(++ir)!=ln.end()?ir->i1:0);
                mg(il!=ln.begin()?(--il)->i2:0,it->i1);
            }
        }
        for(int i=0;i<=ep;++i)if(f[i]==i)id[i]=++idp;
        for(int i=1;i<=n;++i){
            for(int j=0;j<ns[i].e.size();++j){
                edge&e=ns[i].e[j];
            }
        }
        for(int i=0;i<=p;++i)ans[i]=0x7fffffff;
        for(int S=1;S<(1<<p);++S)mxf::cal(S);
        for(int i=1;i<=p;++i)printf("%d
    ",ans[i]);
        return 0;
    }
  • 相关阅读:
    三次请求(读-改-读)引出nibernate 一级缓存
    算法竞赛入门经典第一、二章摘记
    uva 10905 Children's Game
    uva 11205 The broken pedometer
    uva 10160 Servicing stations
    uva 208 Firetruck
    uva 167 The Sultan's Successors
    zoj 1016 Parencodings
    uva 307 Sticks
    uva 216 Getting in Line
  • 原文地址:https://www.cnblogs.com/ccz181078/p/7526656.html
Copyright © 2011-2022 走看看