bzoj3630: [JLOI2014]镜面通道

Description

在一个二维平面上,有一个镜面通道,由镜面AC,BD组成,AC,BD长度相等,且都平行于x轴,B位于(0,0)。通道中有n个外表面为镜面的光学元件,光学元件α为圆形,光学元件β为矩形(这些元件可以与其他元件和通道有交集,具体看下图)。光线可以在AB上任一点以任意角度射入通道,光线不会发生削弱。当出现元件与元件,元件和通道刚好接触的情况视为光线无法透过(比如两圆相切)。现在给出通道中所有元件的信息(α元件包括圆心坐标和半径xi,yi,ri,β元件包括左下角和右上角坐标x1,y1,x2,y2)

1

如上图,S到T便是一条合法线路。

2

当然,显然存在光线无法透过的情况,现在交给你一个艰巨的任务,请求出至少拿走多少个光学元件后,存在一条光线线路可以从CD射出。

下面举例说明:

3

现在假设,取走中间那个矩形,那么就可以构造出一条穿过通道的光路,如图中的S到T。

Input

第一行包含两个整数,x,y,表示C点坐标

第二行包含一个数字,n,表示有n个光学元件

接下来n行

第一个数字如果是1,表示元件α,后面会有三个整数xi,yi,ri分别表示圆心坐标和半径

第一个数字如果是2,表示元件β,后面会有四个整数x1,y1,x2,y2分别表示左下角和右上角坐标(矩形都平行,垂直于坐标轴)

Output

输出包含一行,至少需要拿走的光学元件个数m

Sample Input

1000 100
6
1 500 0 50
2 10 10 20 100
2 100 10 200 100
2 300 10 400 100
2 500 10 600 100
2 700 0 800 100

Sample Output

2

HINT

x<=100000,y<=1000,n<=300

题解

由常识可知,只有元件之间有缝隙时光才能照过去。我们要做的就是试图开辟一道缝隙,这显然是最小割模型。将AC设为源点,BD设为汇点。每个光学元件拆成两个点,中间连一条容量为\(1\)的边。如果两个光学元件相交,从各自的出点向彼此的入点连一条容量为\(inf\)的边。如果光学元件和AC相交,从源点向该元件入点连一条容量为\(1\)的边。如果和BD相交,从光学元件的出点向汇点连容量为\(1\)的边。割掉某条边意味着删掉这个元件,因此最小割即为答案。

判断是否相交的方法可以参考我的代码。貌似和别人的不太一样?

代码

/*
This problem is poisonous???
My code is even more poisonous!!!
*/
#include<bits/stdc++.h>
#define LL long long
#define MAXN 610
#define INF 0x3f3f3f3f
using namespace std;
inline int qr(){
	int x=0,f=0,ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	return f? -x:x;
}

struct Data{
	bool type;//0:circle 1:rectangle
	int xa,ya,xb,yb;
	Data(){}
	Data(bool t,int _x,int _y,int x_,int y_){type=t;xa=_x;ya=_y;xb=x_;yb=y_;}
}p[MAXN];
inline LL Dis(int xa,int ya,int xb,int yb){return 1LL*(xa-xb)*(xa-xb)+1LL*(ya-yb)*(ya-yb);}
inline bool Cir_Cir(Data x,Data y){//two circles
	return 1LL*(x.xb+y.xb)*(x.xb+y.xb)>=Dis(x.xa,x.ya,y.xa,y.ya);
}
inline bool Rec_Rec(Data x,Data y){//two rectangles
	return (x.yb>=y.ya&&y.yb>=x.ya&&x.xb>=y.xa&&y.xb>=x.xa);
}
inline bool Cir_Rec(Data x,Data y){//circle and rectangle
	LL tmp=x.xb*x.xb;
	if(Dis(x.xa,x.ya,y.xa,y.ya)<=tmp)return 1;
	if(Dis(x.xa,x.ya,y.xa,y.yb)<=tmp)return 1;
	if(Dis(x.xa,x.ya,y.xb,y.ya)<=tmp)return 1;
	if(Dis(x.xa,x.ya,y.xb,y.yb)<=tmp)return 1;
	if(x.xa>=y.xa&&x.xa<=y.xb&&abs(x.ya*2-(y.ya+y.yb))<=y.yb-y.ya+x.xb*2)return 1;
	if(x.ya>=y.ya&&x.ya<=y.yb&&abs(x.xa*2-(y.xa+y.xb))<=y.xb-y.xa+x.xb*2)return 1;
	return 0;
}
inline bool Check(Data x,Data y){//judge intersect or not
	if(x.type)swap(x,y);//let x be a circle
	if(!x.type&&!y.type){//two circles
		return Cir_Cir(x,y);
	}
	if(!x.type)return Cir_Rec(x,y);
	return Rec_Rec(x,y);
}

struct Edge{int t,next,v;}e[MAXN*MAXN<<1];
int N,X,Y,S,T,head[MAXN],cnt=1,d[MAXN],tot;
inline void Add_Edge(int from,int to,int cap){
	e[++cnt].t=to;e[cnt].next=head[from];head[from]=cnt;e[cnt].v=cap;
	e[++cnt].t=from;e[cnt].next=head[to];head[to]=cnt;e[cnt].v=0;
}
queue<int>q;
inline bool BFS(){
	memset(d,-1,sizeof(d));
	d[S]=0;q.push(S);
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int i=head[u];i;i=e[i].next){
			int v=e[i].t;
			if(d[v]==-1&&e[i].v)d[v]=d[u]+1,q.push(v);
		}
	}
	return d[T]!=-1;
}
int DFS(int u,int now){
	if(u==T||!now)return now;
	int flow=0,f;
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].t;
		if(d[v]==d[u]+1&&e[i].v&&(f=DFS(v,min(e[i].v,now-flow)))){
			e[i].v-=f;e[i^1].v+=f;flow+=f;
			if(flow==now)return flow;
		}
	}
	if(!flow)d[u]=-1;
	return flow;
}
int op,xa,ya,xb,yb;
int main(){
	freopen("mirror.in","r",stdin);
	freopen("mirror.out","w",stdout);
	X=qr();Y=qr();N=qr();
	for(int i=1;i<=N;i++){
		op=qr();xa=qr();ya=qr();
		if(op==1){
			xb=qr();
			if(xa+xb<0||xa-xb>X||ya+xb<0||ya-xb>Y)continue;
			p[++tot]=Data(0,xa,ya,xb,0);
		}
		else{
			xb=qr();yb=qr();
			if(xb<0||xa>X||yb<0||ya>Y)continue;
			p[++tot]=Data(1,xa,ya,xb,yb);
		}
	}
	N=tot;S=2*N+1;T=S+1;
	for(int i=1;i<=N;i++){
		Add_Edge(i,i+N,1);
		if(p[i].type){
			if(p[i].yb>=Y)Add_Edge(S,i,INF);
			if(p[i].ya<=0)Add_Edge(i+N,T,INF);
		}
		else{
			if(p[i].ya+p[i].xb>=Y)Add_Edge(S,i,INF);
			if(p[i].ya-p[i].xb<=0)Add_Edge(i+N,T,INF);
		}
	}
	for(int i=1;i<=N;i++){
		for(int j=i+1;j<=N;j++){
			if(Check(p[i],p[j]))Add_Edge(i+N,j,INF),Add_Edge(j+N,i,INF);
		}
	}
	int ans=0;
	while(BFS())ans+=DFS(S,INF);
	printf("%d",ans);
	return 0;
}
posted @ 2018-04-12 18:01  lrj998244353  阅读(166)  评论(0编辑  收藏  举报
Live2D