3630: [JLOI2014]镜面通道
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 478 Solved: 166
[ Submit][ Status][ Discuss]
Description
在一个二维平面上,有一个镜面通道,由镜面AC,BD组成,AC,BD长度相等,且都平行于x轴,B位于(0,0)。通道中有n个外表面为镜面的光学元件,光学元件α为圆形,光学元件β为矩形(这些元件可以与其他元件和通道有交集,具体看下图)。光线可以在AB上任一点以任意角度射入通道,光线不会发生削弱。当出现元件与元件,元件和通道刚好接触的情况视为光线无法透过(比如两圆相切)。现在给出通道中所有元件的信息(α元件包括圆心坐标和半径xi,yi,ri,β元件包括左下角和右上角坐标x1,y1,x2,y2)
如上图,S到T便是一条合法线路。
当然,显然存在光线无法透过的情况,现在交给你一个艰巨的任务,请求出至少拿走多少个光学元件后,存在一条光线线路可以从CD射出。
下面举例说明:
现在假设,取走中间那个矩形,那么就可以构造出一条穿过通道的光路,如图中的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
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
Source
这个题啊,Excited!网络流最小割嘛,把每个图形拆点,即第i个图形向第i+n个图形连流量为1的无向边
如果一个图形与另一个图形相交,就连流量为INF的无向边
判相交的话,就是矩形与圆相交,搞一个计算几何求点到线段距离就好了
PS:与边界相交可以把边界视为矩形搞。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 910
#define maxm 300100
#define pf(x) (1ll*(x)*(x))
using namespace std;
int n,bg,ed,head[maxn],dep[maxn],q[maxn],ql,qr,esz=2;
long long x,y;
struct edge{
int r,nxt,w;
}e[maxm];
struct Vector{
double x,y;
Vector(){}
Vector(double x,double y):x(x),y(y){}
Vector operator-(const Vector& vec)const{
return Vector(x-vec.x,y-vec.y);
}
};
double cross(const Vector& a,const Vector& b){
return a.x*b.y-a.y*b.x;
}
double dot(const Vector& a,const Vector& b){
return a.x*b.x+a.y*b.y;
}
double length(const Vector& a){
return sqrt((double)dot(a,a));
}
double distoseg(const Vector x,const Vector a,const Vector b){
Vector v1=b-a,v2=x-a,v3=x-b;
if(dot(v1,v2)<0)return length(v2);
if(dot(v1,v3)>0)return length(v3);
return ((double)abs(cross(v1,v2)))/length(v1);
}
int dcmp(double a){
return fabs(a)<1e-7?0:(a>0?1:-1);
}
struct data{
long long x1,y1,x2,y2,att;
void circle(long long x,long long y,long long r){
x1=x;y1=y;x2=r;att=1;
}
void square(long long x1,long long y1,long long x2,long long y2){
this->x1=x1;this->x2=x2;
this->y1=y1;this->y2=y2;
att=2;
}
}d[maxn];
void addedge(int u,int v,int w){
// printf("[%d,%d]\n",u,v);
e[esz].r=v;e[esz].nxt=head[u];
e[esz].w=w;head[u]=esz++;
e[esz].r=u;e[esz].nxt=head[v];
e[esz].w=0;head[v]=esz++;
}
bool isincir(long long x1,long long y1,data& d){
return pf(x1-d.x1)+pf(y1-d.y1)<=pf(d.x2);
}
bool isinsq(long long x1,long long y1,data& d){
return d.x1<=x1&&x1<=d.x2&&d.y1<=y1&&y1<=d.y2;
}
bool cirandcir(data& x,data& y){
return pf(x.x1-y.x1)+pf(x.y1-y.y1)<=pf(x.x2+y.x2);
}
bool pd(long long x1,long long y1,long long x2,long long y2,long long x,long long y,long long r){
return dcmp(distoseg(Vector(x,y),Vector(x1,y1),Vector(x2,y2))-r)<=0;
}
bool bfs(){
ql=qr=0;
q[qr++]=bg;
memset(dep,0,sizeof(dep));
dep[bg]=1;
while(ql<qr){
int x=q[ql++];
for(int t=head[x];t;t=e[t].nxt)if(!dep[e[t].r]&&e[t].w)
dep[e[t].r]=dep[x]+1,q[qr++]=e[t].r;
}
return dep[ed]!=0;
}
int find(int u,int flow){
if(u==ed)return flow;
int a=0,used=0;
for(int t=head[u];t;t=e[t].nxt)if(e[t].w&&dep[e[t].r]==dep[u]+1&&(a=find(e[t].r,min(flow,e[t].w)))){
e[t].w-=a;e[t^1].w+=a;
used+=a;
if(used==flow)return used;
}
if(!used)dep[u]=0;
return used;
}
bool check(int i,int j){
if(d[i].att==1&&d[j].att==1){
if(cirandcir(d[i],d[j])||cirandcir(d[i],d[j]))
return true;
} else if(d[i].att==2&&d[j].att==2){
if(isinsq(d[i].x1,d[i].y1,d[j])||isinsq(d[i].x2,d[i].y1,d[j])
||isinsq(d[i].x1,d[i].y2,d[j])||isinsq(d[i].x2,d[i].y2,d[j])||
isinsq(d[j].x1,d[j].y1,d[i])||isinsq(d[j].x2,d[j].y1,d[i])
||isinsq(d[j].x1,d[j].y2,d[i])||isinsq(d[j].x2,d[j].y2,d[i]))
return true;
} else {
int ni=i,nj=j;
if(d[ni].att==2&&d[nj].att==1)swap(ni,nj);
if(pd(d[nj].x1,d[nj].y1,d[nj].x1,d[nj].y2,d[ni].x1,d[ni].y1,d[ni].x2))return true;
else if(pd(d[nj].x1,d[nj].y2,d[nj].x2,d[nj].y2,d[ni].x1,d[ni].y1,d[ni].x2))return true;
else if(pd(d[nj].x2,d[nj].y2,d[nj].x2,d[nj].y1,d[ni].x1,d[ni].y1,d[ni].x2))return true;
else if(pd(d[nj].x2,d[nj].y1,d[nj].x1,d[nj].y1,d[ni].x1,d[ni].y1,d[ni].x2))return true;
}
return false;
}
int main(){
scanf("%lld%lld%d",&x,&y,&n);
for(int i=1;i<=n;++i){
int op;scanf("%d",&op);
if(op==1){
long long x,y,r;scanf("%lld%lld%lld",&x,&y,&r);
d[i].circle(x,y,r);
} else {
long long x1,y1,x2,y2;
scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
d[i].square(x1,y1,x2,y2);
}
}
d[n+1].square(0,y,x,1ll<<60);
d[n+2].square(0,-1ll<<60,1ll<<60,0);
for(int i=1;i<=n;++i)addedge(i,i+n,1),addedge(i+n,i,1);
for(int i=1;i<=n;++i)
for(int j=i+1;j<=n;++j)
if(check(i,j)) addedge(i+n,j,1<<30),addedge(j+n,i,1<<30);
bg=0,ed=n*2+1;
for(int i=1;i<=n;++i)if(check(n+1,i))addedge(i+n,ed,1<<30);
for(int i=1;i<=n;++i)if(check(n+2,i))addedge(bg,i,1<<30);
int ans=0,f=0;
while(bfs())while(f=find(bg,1<<30))ans+=f;
printf("%d",ans);
}