[bzoj3630][JLOI2014]鏡面通道_計算幾何_網路流_最小割
阿新 • • 發佈:2019-01-09
鏡面通道 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); }
小結:好題好題。就是特判有點噁心。