首页 > 其他分享 >【题解】[JLOI2014]镜面通道

【题解】[JLOI2014]镜面通道

时间:2023-06-14 14:35:23浏览次数:74  
标签:JLOI2014 return int 题解 1205 镜面 double cr 元件

题目描述:

在一个二维平面上,有一个镜面通道,由镜面 \(AC, BD\) 组成,\(AC, BD\) 长度相等,且都平行于 \(x\) 轴,\(B\) 位于 \((0,0)\)。

通道中有 \(n\) 个外表面为镜面的光学元件,光学元件 \(\alpha\) 为圆形,光学元件 \(\beta\) 为矩形(这些元件可以与其他元件和通道有交集,具体看下图)。光线可以在 \(AB\) 上任一点以任意角度射入通道,光线不会发生削弱。当出现元件与元件,元件和通道刚好接触的情况视为光线无法透过(比如两圆相切)。

现在给出通道中所有元件的信息(\(\alpha\) 元件包括圆心坐标和半径 \(x_i, y_i, r_i\),\(\beta\) 元件包括左下角和右上角坐标 \(x_1, y_1, x_2, y_2\))

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

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

下面举例说明:

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

\(x\leq 10^5\),\(y\leq 1000\),\(n\leq 300\)。

题目分析:

有一个显然的结论:如果我们任意方向走可以走通,那么就有解,也就是只要镜面中间有缝可以过去就有解。
那么就考虑怎么判断,显然需要转化为图论模型,考虑对于每一个元件建一个点,对于有交的元件之间连边。
因为会发现这个有缝就可以理解为上下不连通也就是最小割模型,所以我们只需要将 AC 作为源点,BD 作为汇点跑一个最小割就好了
需要注意的就是:我们的操作为删点而非删边,所以我们应该将每一个点拆点,在拆成的两个点之间连流量为 \(1\) 的边,此时删边一定不比删点优,所以最小割都为删点。

代码:

(直接复制的题解的,因为计算几何部分太难写了)

点击查看代码

#include<bits/stdc++.h>
using namespace std;const double eps=1e-7;const int INF=1e9;
struct rnd{double x,y,r;int id;}a[1205];
struct squ{double x1,y1,x2,y2;int id;}b[1205];
struct edge{int to,w,nxt;}e[2000005];
double Cx,Cy;int n,et,s,t,head[1205],d[1205],cr[1205],ac,bc;
inline char chk(squ a,double x,double y) {return a.x1-eps<=x&&x<=a.x2+eps&&a.y1-eps<=y&&y<=a.y2+eps;}
inline char CHK(squ a,double y,double x1,double x2) {return (a.y1-eps<=y&&y<=a.y2+eps)||chk(a,x1,y)||chk(a,x2,y);}
inline char chk1(rnd a,double x,double y1,double y2)
{
	if((a.x-x)*(a.x-x)+(a.y-y1)*(a.y-y1)<=a.r*a.r+eps) return 1;
	if((a.x-x)*(a.x-x)+(a.y-y2)*(a.y-y2)<=a.r*a.r+eps) return 1;
	if(!(a.x-x<=a.r+eps&&a.x-x>=a.r-eps)) return 0;
	double dy=sqrt(a.r*a.r-(a.x-x)*(a.x-x)),Y1=a.y-dy,Y2=a.y+dy;
	return (y1-eps<=Y1&&Y1<=y2+eps)||(y1-eps<=Y2&&Y2<=y2+eps);
}
inline char chk2(rnd a,double y,double x1,double x2)
{
	if((a.x-x1)*(a.x-x1)+(a.y-y)*(a.y-y)<=a.r*a.r+eps) return 1;
	if((a.x-x2)*(a.x-x2)+(a.y-y)*(a.y-y)<=a.r*a.r+eps) return 1;
	if(!(a.y-y<=a.r+eps&&a.y-y>=-a.r-eps)) return 0;
	double dx=sqrt(a.r*a.r-(a.y-y)*(a.y-y)),X1=a.x-dx,X2=a.x+dx;
	return (x1-eps<=X1&&X1<=x2+eps)||(x1-eps<=X2&&X2<=x2+eps);
}
inline char operator+(rnd a,rnd b) {return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)<=(a.r+b.r+eps)*(a.r+b.r+eps);}
inline char operator+(squ a,squ b) {return chk(a,b.x1,b.y1)||chk(a,b.x1,b.y2)||chk(a,b.x2,b.y1)||chk(a,b.x2,b.y2);}
inline char operator+(squ a,rnd b)
{
	if((a.x1-b.x)*(a.x1-b.x)+(a.y1-b.y)*(a.y1-b.y)<=b.r*b.r+eps) return 1;
	if((a.x2-b.x)*(a.x2-b.x)+(a.y1-b.y)*(a.y1-b.y)<=b.r*b.r+eps) return 1;
	if((a.x1-b.x)*(a.x1-b.x)+(a.y2-b.y)*(a.y2-b.y)<=b.r*b.r+eps) return 1;
	if((a.x2-b.x)*(a.x2-b.x)+(a.y2-b.y)*(a.y2-b.y)<=b.r*b.r+eps) return 1;
	if(chk(a,b.x,b.y)) return 1;
	if(chk1(b,a.x1,a.y1,a.y2)||chk1(b,a.x2,a.y2,a.y2)||chk2(b,a.y1,a.x1,a.x2)||chk2(b,a.y2,a.x1,a.x2)) return 1;
	return 0;
}
inline void ADDE(int x,int y,int w) {e[++et]=(edge){y,w,head[x]},head[x]=et;}
inline void adde(int x,int y,int w) {ADDE(x,y,w),ADDE(y,x,0);}
inline char bfs(int s,int t)
{
	queue<int>q;q.push(s),memset(d,0,sizeof(d)),d[s]=1;
	while(!q.empty())
	{
		int x=q.front();q.pop();
		for(int i=head[x];i;i=e[i].nxt) if(e[i].w&&!d[e[i].to]) d[e[i].to]=d[x]+1,q.push(e[i].to);
	}
	return !!d[t];
}
#define rev(x) ((((x)&1)?1:-1)+(x))
inline int dfs(int x,int t,int lim=INF)
{
	int f=lim;if(x==t) return lim;
	for(int i=cr[x];i;cr[x]=i=e[i].nxt) if(d[e[i].to]==d[x]+1&&e[i].w)
	{
		int g=dfs(e[i].to,t,min(f,e[i].w));f-=g;
		e[i].w-=g,e[rev(i)].w+=g;if(!f) break;
	}
	return lim-f;
}
inline int dinic(int s,int t) {int r=0;while(bfs(s,t)) memcpy(cr,head,sizeof(cr)),r+=dfs(s,t);return r;}
int main()
{
	scanf("%lf%lf%d",&Cx,&Cy,&n),et=0,memset(head,0,sizeof(head)),s=n<<1|1,t=s+1;
	for(int i=1,fg;i<=n;i++)
	{
		scanf("%d",&fg);if(fg^2) ++ac,scanf("%lf%lf%lf",&a[ac].x,&a[ac].y,&a[ac].r),a[ac].id=i;
		else bc++,scanf("%lf%lf%lf%lf",&b[bc].x1,&b[bc].y1,&b[bc].x2,&b[bc].y2),b[bc].id=i;
	}
	for(int i=1;i<=n;i++) adde(i,i+n,1);
	for(int i=1;i<=ac;i++) if(chk2(a[i],0,0,Cx)) adde(s,a[i].id,1);
	for(int i=1;i<=bc;i++) if(CHK(b[i],0,0,Cx)) adde(s,b[i].id,1);
	for(int i=1;i<=ac;i++) if(chk2(a[i],Cy,0,Cx)) adde(a[i].id+n,t,1);
	for(int i=1;i<=bc;i++) if(CHK(b[i],Cy,0,Cx)) adde(b[i].id+n,t,1);
	for(int i=1;i<=ac;i++) for(int j=1;j<=ac;j++) if(i!=j&&a[i]+a[j]) adde(a[i].id+n,a[j].id,1);
	for(int i=1;i<=bc;i++) for(int j=1;j<=ac;j++) if(i!=j&&b[i]+a[j]) adde(b[i].id+n,a[j].id,1);
	for(int i=1;i<=ac;i++) for(int j=1;j<=bc;j++) if(i!=j&&b[j]+a[i]) adde(a[i].id+n,b[j].id,1);
	for(int i=1;i<=bc;i++) for(int j=1;j<=bc;j++) if(i!=j&&(b[i]+b[j]||b[j]+b[i])) adde(b[i].id+n,b[j].id,1);
	return printf("%d\n",dinic(s,t)),0;
}

标签:JLOI2014,return,int,题解,1205,镜面,double,cr,元件
From: https://www.cnblogs.com/linyihdfj/p/17480095.html

相关文章

  • HarmonyOS在SDK9版本下FA模型geolocation无法定位问题解决
    问题描述已经在config.json中加入了ohos.permission.LOCATION权限声明,但是在实际开发中,我使用geolocation.getCurrentLocation().then((result)=>{this.locationInfo=JSON.stringify(result);this.blog.setTitle(this.locationInfo);});获取位置信息得不到结果我使用的......
  • POJ2117 Electricity 题解 tarjan点双连通分量 割点
    题目链接:http://poj.org/problem?id=2117题目大意:给定一个由\(n\)个点\(m\)条边构成的无向图,请你求出该图删除一个点之后,连通块最多有多少。解题思路:tarjan,判断\(u\)的子节点有几个\(v\)满足\(low[v]\gedfn[u]\)就是答案,但是同时如果\(u\)不是这个dfs树的根节......
  • CF1697F 题解
    题意传送门构造一个长度为\(n\)的数列\(a\),满足\(1\lea_i\lek\)且\(a\)不降,以及\(m\)个约束,有三种情况:1ix,表示\(a_i\nex\)2ijx,表示\(a_i+a_j\lex\)3ijx,表示\(a_i+a_j\gex\)无解输出\(-1\)。\(1\len,m\le2\times10^4,2\lek\le10\)。题......
  • 【Android】ListView与Button的共存问题解决
    【Android】ListView与Button的共存问题解决这两天在捣鼓ListViewwidget,为了在ListView中加入Button这类的有“点击”事件的widget,请教了不少高手,感谢LandMark对我的认真讲解,下面把解决过程描述一下。 ListView和其它能触发点击事件的widget无法一起正常工作的......
  • P2860 [USACO06JAN]Redundant Paths G 题解 ratjan边双连通分量
    题目链接:https://www.luogu.com.cn/problem/P2860题目大意:给定一个无向连通图,求至少加几条边,能使其变成一个边双连通图。解题思路:边双连通分量缩点后计算度数为\(1\)的节点个数,假设有\(cnt\)个,则答案为\((cnt+1)/2\)。示例程序:#include<bits/stdc++.h>usingnamespac......
  • Educational Codeforces Round 150 (Rated for Div. 2) 题解
    https://codeforces.com/contest/1841https://codeforces.com/contest/1841/problemsD.PairsofSegmentshttps://codeforces.com/contest/1841/problem/D因为\(n\)只有\(2000\),所以考虑枚举每一对\((i,j)\)满足区间有交集并且\(i\neqj\)。如果有交集,就合并。然后......
  • 题解 P9196【[JOI Open 2016] 销售基因链】
    套路题,来讲个套路解法。如果没有后缀的要求,答案就是trie树的子树内字符串数量。现在加上了后缀,尝试继续使用trie树解决问题。我们建立两棵trie树\(T_1,T_2\),其中\(T_1\)是正常的trie树,\(T_2\)是每个字符串翻转后的trie树。这样的话,包含给定后缀的字符串在\(T_2\)......
  • C++ Windows.h max宏与std::max冲突问题解决
    C语言引入的宏支持了一定程度的元编程,但它仅仅是简单的字符串替换,这种“六亲不认”的操作很容易导致一些编译错误。这篇文章介绍了一种场景:项目同时引入了老的C头文件,里面用宏定义了一些宏函数;还引入了C++的头文件,里面用其他方式定义了一些同名函数。具体到问题本身,这个......
  • Not Another Linear Algebra Problem 题解
    题意:自己看。首先我们知道我们唯一能找到的题解在hos_lyric的代码里。把它放在这里:(由bikuhiku提供)\[\begin{aligned}&U\subseteq\mathbb{F}_p^n,\text{subspace}\\&a(U):=\#\{p\in\text{Aut}(\mathbb{F}_p^n)|\text{Ker}(p-\text{id})=U\}\\&b(U):=......
  • 【问题解决1】fatal error: X11/XXXX.h: No such file or directory
    问题现象编译鸿蒙代码时,报如下类似的错误:错误1:错误2:解决方法step1:安装依赖文件sudoapt-getinstallapt-filesudoapt-fileupdatestep2:查找报错文件apt-filesearchXXXX.h例如:报错的是Intrinsic.h或上图中的Xrandr.h,对应如下:apt-filesearchIntrinsic......