bzoj3630 [JLOI2014]鏡面通道
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的邊。
就完成了。
說一下如何判相交
圓和圓就看圓心距是否小於兩圓半徑和
矩形和矩形就看兩矩形中心橫座標之差是否小於兩矩形橫著的邊長和的一半,兩矩形中心縱座標之差是否小於兩矩形豎著的邊長和的一半
圓和矩形相交就看圓到矩形的最短距離
先看圓心是否在矩形內,是則一定能夠相交;
否則看圓心是否在矩形橫長的範圍內,是則最近距離是圓心到離他最近的橫邊的垂直距離;
否則看圓心是否在矩形豎長的範圍內,是則最近距離是圓心到離他最近的豎邊的垂直距離;
否則最近距離是圓心到離它最近的矩形頂點的距離
然後判一下最近距離和半徑的關係就好
水到爆的題。。。純考幾何還有碼力。。
#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;
}