BZOJ3630 : [JLOI2014]镜面通道

从左边不能到达右边当且仅当存在一条与上下底边相连的分割线将它们分开

设下底边为S,上底边为T,每个元件作为点,有公共部分的两个点互相连边

最后拆点求最小割

 

#include<cstdio>

#include<cmath>

#include<algorithm>

using namespace std;

const int N=620,inf=~0U>>2;

int n,i,j,x,y,S,T,h[N],gap[N],ans;

struct P{int x1,y1,x2,y2,r,t,x,y;}a[N];

struct edge{int t,f;edge *nxt,*pair;}*g[N],*d[N];

inline void add(int s,int t,int f){

  edge *p=new(edge);p->t=t;p->f=f;p->nxt=g[s];g[s]=p;

  p=new(edge);p->t=s;p->f=0;p->nxt=g[t];g[t]=p;

  g[s]->pair=g[t];g[t]->pair=g[s];

}

int sap(int v,int flow){

  if(v==T)return flow;

  int rec=0;

  for(edge*p=d[v];p;p=p->nxt)if(h[v]==h[p->t]+1&&p->f){

    int ret=sap(p->t,std::min(flow-rec,p->f));

    p->f-=ret;p->pair->f+=ret;d[v]=p;

    if((rec+=ret)==flow)return flow;

  }

  d[v]=g[v];

  if(!(--gap[h[v]]))h[S]=T;

  gap[++h[v]]++;

  return rec;

}

inline int sqr(int x){return x*x;}

inline double dis(int x1,int y1,int x2,int y2){return sqrt(sqr(x1-x2)+sqr(y1-y2))-1e-8;}

inline bool check(P a,P b){

  if(a.t==1&&b.t==1)return dis(a.x,a.y,b.x,b.y)<=1.0*a.r+b.r;

  if(a.t==2&&b.t==1){P c=a;a=b;b=c;}

  if(a.t==1&&b.t==2){

    if(dis(a.x,a.y,b.x1,b.y1)<=a.r)return 1;

    if(dis(a.x,a.y,b.x1,b.y2)<=a.r)return 1;

    if(dis(a.x,a.y,b.x2,b.y1)<=a.r)return 1;

    if(dis(a.x,a.y,b.x2,b.y2)<=a.r)return 1;

    if(b.x2>a.x&&b.x1<a.x)if(fabs(b.y2-a.y)<=a.r||fabs(b.y1-a.y)<=a.r)return 1;

    if(b.y2>a.y&&b.y1<a.y)if(fabs(b.x2-a.x)<=a.r||fabs(b.x1-a.x)<=a.r)return 1;

    return b.x1<=a.x&&a.x<=b.x2&&b.y1<=a.y&&a.y<=b.y2;

  }

  return !(b.x2<a.x1||b.x1>a.x2||b.y2<a.y1||b.y1>a.y2);

}

int main(){

  scanf("%d%d%d",&x,&y,&n);S=n*2+1,T=S+1;

  for(i=1;i<=n;i++)add(i,i+n,1),add(i+n,i,1);

  a[0].t=2,a[0].y1=-1,a[0].x2=x;

  a[n+1].t=2,a[n+1].y1=y,a[n+1].x2=x,a[n+1].y2=y+1;

  for(i=1;i<=n;i++){

    scanf("%d",&a[i].t);

    if(a[i].t==1)scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].r);else scanf("%d%d%d%d",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2);

    for(j=1;j<i;j++)if(check(a[i],a[j]))add(i+n,j,inf),add(j+n,i,inf);

  }

  for(i=1;i<=n;i++)if(check(a[i],a[0]))add(S,i,inf);

  for(i=1;i<=n;i++)if(check(a[i],a[n+1]))add(i+n,T,inf);

  for(gap[i=0]=T;i<=T;i++)d[i]=g[i];

  while(h[S]<T)ans+=sap(S,inf);

  return printf("%d",ans),0;

}

  

 

你可能感兴趣的:(ZOJ)