bzoj2965: 保护古迹
Posted ccz181078
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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\n",ans[i]); return 0; }
以上是关于bzoj2965: 保护古迹的主要内容,如果未能解决你的问题,请参考以下文章