bzoj3630 [JLOI2014]镜面通道
2018-01-13 08:23
417 查看
3630: [JLOI2014]镜面通道
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 574 Solved: 214
[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
Sample Output
2
HINT
x<=100000,y<=1000,n<=300
题解:
咳咳。
这题目很玄妙,它是个比较隐蔽的最小割。
应用到了一个物理知识:
水(蚂蚁/空气)可以过的地方,光也能过。
因此这题就是在问要删去几个原件可以使上下不连通。
是不是很像网络流QwQ
拆点,因只能删下去一次,入点到出点连流量为一的边
两个相交的原件连inf的边
注意:两个相交的原件间连两条边!即a的出点到b的入点一条,b的出点到a的入点一条
与上面相交的连一条inf的边,与下面相交的连一条inf的边。
就完成了。
说一下如何判相交
圆和圆就看圆心距是否小于两圆半径和
矩形和矩形就看两矩形中心横坐标之差是否小于两矩形横着的边长和的一半,两矩形中心纵坐标之差是否小于两矩形竖着的边长和的一半
圆和矩形相交就看圆到矩形的最短距离
先看圆心是否在矩形内,是则一定能够相交;
否则看圆心是否在矩形横长的范围内,是则最近距离是圆心到离他最近的横边的垂直距离;
否则看圆心是否在矩形竖长的范围内,是则最近距离是圆心到离他最近的竖边的垂直距离;
否则最近距离是圆心到离它最近的矩形顶点的距离
然后判一下最近距离和半径的关系就好
水到爆的题。。。纯考几何还有码力。。
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 574 Solved: 214
[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
Sample Output
2
HINT
x<=100000,y<=1000,n<=300
题解:
咳咳。
这题目很玄妙,它是个比较隐蔽的最小割。
应用到了一个物理知识:
水(蚂蚁/空气)可以过的地方,光也能过。
因此这题就是在问要删去几个原件可以使上下不连通。
是不是很像网络流QwQ
拆点,因只能删下去一次,入点到出点连流量为一的边
两个相交的原件连inf的边
注意:两个相交的原件间连两条边!即a的出点到b的入点一条,b的出点到a的入点一条
与上面相交的连一条inf的边,与下面相交的连一条inf的边。
就完成了。
说一下如何判相交
圆和圆就看圆心距是否小于两圆半径和
矩形和矩形就看两矩形中心横坐标之差是否小于两矩形横着的边长和的一半,两矩形中心纵坐标之差是否小于两矩形竖着的边长和的一半
圆和矩形相交就看圆到矩形的最短距离
先看圆心是否在矩形内,是则一定能够相交;
否则看圆心是否在矩形横长的范围内,是则最近距离是圆心到离他最近的横边的垂直距离;
否则看圆心是否在矩形竖长的范围内,是则最近距离是圆心到离他最近的竖边的垂直距离;
否则最近距离是圆心到离它最近的矩形顶点的距离
然后判一下最近距离和半径的关系就好
水到爆的题。。。纯考几何还有码力。。
#include<iostream> #include<iomanip> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> using namespace std; #define MAXN 100000 #define inf (1<<29) struct rec { double x1,x2,y1,y2; double ly,lx; }Rec[310]; struct cir { double x,y,r; }Cir[310]; int nc,nr; int X,Y; struct edge { int to,nxxt,weight; }e[MAXN<<2]; int q[MAXN]; int head[MAXN]; int dep[MAXN]; int frontt,backk; int S,T; int cnt=-1; int ans; inline void add(int s,int q,int c) { cnt++; e[cnt].to=q; e[cnt].nxxt=head[s]; e[cnt].weight=c; head[s]=cnt; } inline void in(int from,int to,int val) { add(from,to,val); add(to,from,0); } inline bool bfs() { frontt=1;backk=0; memset(dep,-1,sizeof(dep)); q[++backk]=S; dep[S]=0; while(frontt<=backk) { int x=q[frontt++]; for(int i=head[x];i!=-1;i=e[i].nxxt) { int t=e[i].to,w=e[i].weight; if(dep[t]==-1&&w>0) { dep[t]=dep[x]+1; q[++backk]=t; } } } return dep[T]!=-1?1:0; } inline int dfs(int x,int v) { if(x==T||v==0)return v; int maxx=0; for(int i=head[x];i!=-1;i=e[i].nxxt) { int t=e[i].to,w=e[i].weight; if(dep[t]==dep[x]+1&&w>0) { int f=dfs(t,min(v,w)); if(f) { e[i].weight-=f; e[i^1].weight+=f; maxx+=f; v-=f; if(v==0)break; } } } if(!maxx)dep[x]=-1; return maxx; } inline void dinic() { ans=0; while(bfs()) { ans+=dfs(S,inf); } } double dis(double x1,double x2,double y1,double y2) { return sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)); } bool circross(int a,int b) { if(dis(Cir[a].x, Cir[b].x, Cir[a].y, Cir[b].y)<= (Cir[a].r+Cir[b].r))return 1; return 0; } bool reccross(int a,int b) { double xa,ya,xb,yb; xa=(Rec[a].x1+Rec[a].x2)/2; xb=(Rec[b].x1+Rec[b].x2)/2; ya=(Rec[a].y1+Rec[a].y2)/2; yb=(Rec[b].y1+Rec[b].y2)/2; if(abs(xb-xa)<=((Rec[a].lx+Rec[b].lx)/2)&&abs(yb-ya)<=((Rec[a].ly+Rec[b].ly)/2))return 1; return 0; } bool inside(int c,int r) { if(Cir[c].x<=Rec[r].x2&&Cir[c].x>=Rec[r].x1&&Cir[c].y<=Rec[r].y2&&Cir[c].y>=Rec[r].y1)return 1; return 0; } double mindist(int c,int r) { if(Cir[c].x<=Rec[r].x2&&Cir[c].x>=Rec[r].x1) { if(Cir[c].y<=Rec[r].y1)return (Rec[r].y1-Cir[c].y); else return (Cir[c].y-Rec[r].y2); } else if(Cir[c].y<=Rec[r].y2&&Cir[c].y>=Rec[r].y1) { if(Cir[c].x<=Rec[r].x1)return (Rec[r].x1-Cir[c].x); else return (Cir[c].x-Rec[r].x2); } else { if(Cir[c].x<=Rec[r].x1&&Cir[c].y<=Rec[r].y1) { return dis(Cir[c].x,Rec[r].x1,Cir[c].y,Rec[r].y1); } else if(Cir[c].x<=Rec[r].x1&&Cir[c].y>=Rec[r].y2) { return dis(Cir[c].x,Rec[r].x1,Cir[c].y,Rec[r].y2); } else if(Cir[c].x>=Rec[r].x2&&Cir[c].y>=Rec[r].y2) { return dis(Cir[c].x,Rec[r].x2,Cir[c].y,Rec[r].y2); } else { return dis(Cir[c].x,Rec[r].x2,Cir[c].y,Rec[r].y1); } } } bool rec_cir_cross(int c,int r) { if(inside(c,r))return 1; if(mindist(c,r)<=Cir[c].r)return 1; return 0; } inline int read() { int s=0,w=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') { w=-1; } ch=getchar(); } while(ch>='0'&&ch<='9') { s=s*10+ch-'0'; ch=getchar(); } return s*w; } inline void print(int x) { if(x<0) { x=-x; putchar('-'); } if(x>=10) { print(x/10); } putchar(x%10+'0'); } int n; int main() { memset(head,-1,sizeof(head)); X=read();Y=read(); n=read(); S=0,T=n<<1|1; for(int i=1;i<=n;i++) { if(read()==1) { Cir[++nc].x=read(); Cir[nc].y=read(); Cir[nc].r=read(); } else { Rec[++nr].x1=read(); Rec[nr].y1=read(); Rec[nr].x2=read(); Rec[nr].y2=read(); Rec[nr].ly=abs(Rec[nr].y1-Rec[nr].y2); Rec[nr].lx=abs(Rec[nr].x1-Rec[nr].x2); } } /*int m=read(); for(int i=1;i<=m;i++) { int j=read(); int k=read(); if(rec_cir_cross(j,k))cout<<"Yes"<<endl; else cout<<"No"<<endl; }*/ for(int i=1;i<=nr;i++) { for(int j=i+1;j<=nr;j++) { if(reccross(i,j))in(i+n,j,inf),in(j+n,i,inf); } } for(int i=1;i<=nc;i++) { for(int j=i+1;j<=nc;j++) { if(circross(i,j))in(i+nr+n,j+nr,inf),in(j+nr+n,i+nr,inf); } } for(int i=1;i<=nc;i++) { for(int j=1;j<=nr;j++) { if(rec_cir_cross(i,j))in(i+nr+n,j,inf),in(j+n,i+nr,inf); } } for(int i=1;i<=nr;i++) { in(i,i+n,1); if(Rec[i].y2>=Y)in(S,i,inf); if(Rec[i].y1<=0)in(i+n,T,inf); } for(int i=1;i<=nc;i++) { in(i+nr,i+nr+n,1); if(Cir[i].y+Cir[i].r>=Y)in(S,i+nr,inf); if(Cir[i].y-Cir[i].r<=0)in(i+nr+n,T,inf); } dinic(); print(ans); putchar(10); return 0; }
相关文章推荐
- 【bzoj 3630】: [JLOI2014]镜面通道
- 【bzoj3630】[JLOI2014]镜面通道 对偶图+计算几何+网络流最小割
- bzoj 3630 [JLOI2014]镜面通道 计算几何 网络流
- BZOJ3630 : [JLOI2014]镜面通道
- BZOJ3630: [JLOI2014]镜面通道
- BZOJ 3630 JLOI2014 镜面通道 计算几何+最小点割集
- 【BZOJ3630】[JLOI2014]镜面通道 几何+最小割
- BZOJ 3630 JLOI 2013 镜面通道 最小点割集
- BZOJ3630: [JLOI2014]镜面通道 最小割
- bzoj3630 镜面通道 网络流
- bzoj3630: [JLOI2014]镜面通道
- bzoj 3629: [JLOI2014]聪明的燕姿
- BZOJ3627 [JLOI2014]路径规划
- Bzoj3631: [JLOI2014]松鼠的新家
- bzoj3629[JLOI2014]聪明的燕姿
- bzoj 3631: [JLOI2014]松鼠的新家
- bzoj 3629: [JLOI2014]聪明的燕姿【线性筛+dfs】
- BZOJ 3627 JLOI 2014 路径规划 分层图 SPFA+HEAP
- [BZOJ3631]JLOI2014松鼠的新家|树上差分
- bzoj 3631: [JLOI2014]松鼠的新家(LCA+树上差分)