码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj2965: 保护古迹

时间:2017-09-15 16:38:59      阅读:202      评论:0      收藏:0      [点我收藏+]

标签:相交   des   names   return   font   设计   ==   整数   正整数   

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\n",ans[i]);
    return 0;
}

 

bzoj2965: 保护古迹

标签:相交   des   names   return   font   设计   ==   整数   正整数   

原文地址:http://www.cnblogs.com/ccz181078/p/7526656.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!