zoukankan      html  css  js  c++  java
  • JZOJ 3956. 【GDOI2015模拟12.20】鸡腿の梦境(计算几何)

    JZOJ 3956. 【GDOI2015模拟12.20】鸡腿の梦境

    题目

    Description

    【故事の背景】

    鸡腿是CZYZ的著名DS,他为了树立高富帅的伟大形象决定暑假去张江大学学习(游玩)。去的第一天晚上因为蚊子很多,鸡腿不堪其扰怒而打了一夜游戏。 第二天鸡腿吸取教训,弄好了蚊帐,自然是睡了一个好觉。鸡腿似乎还记得做的那个梦……

    【问题の描述】

    鸡腿做了一个好梦呢!他化身钢铁侠大战全宇宙的各种怪物,并且取得了胜利。在梦的结尾,鸡腿开的飞船困在了一片废弃飞船群中,同时由于引擎故障,他只能在平面内移动。废弃飞船群可以描述为许多圆形的飞船,当然因为各种奇怪的原因,飞船可能叠加在一切。鸡腿也驾驶着飞船在这个平面中。一开始的时候鸡腿的飞船是不会和废弃的飞船有叠加部分的,鸡腿驶出这片区域时,可以蹭过某一个废弃飞船,但不能撞上更不能挤开它(质量问题),更不能和废弃飞船叠起来。鸡腿要立刻离开这片区域进行补给,你能告诉他现有条件下可以离开这片废弃飞船群吗?

    Input

    有多组数据,文件以EOF结束。
    每组数据第一行一个整数N,表示有N个废弃飞船组成废弃飞船群。
    接下来N行每行三个实数,Xi、Yi、Ri表示废弃飞船圆心坐标和半径。
    最后一行三个实数表示鸡腿驾驶飞船的圆心位置和半径。
    数据保证一开始位置合法。

    Output

    对于每一组数据,如果可行请输出“YES”,否则输出“NO”,输出后换行。

    Sample Input

    输入1:
    7
    2 2 1.1
    -2 2 1.1
    2 -2 1.0
    -2 -2 1.0
    2 -5 1.0
    0 -8 1.0
    -2 -6 1.0
    0 0 1
    输入2:
    5
    2 2 1.1
    -2 2 1.1
    2 -2 1.0
    -2 -2 1.0
    0 -3 0.01
    0 0 1

    Sample Output

    输出1:
    YES
    输出2:
    NO

    Data Constraint

    对于30%的数据N ≤ 15;
    对于40%的数据 N ≤ 150;
    对于 100%的数据 N ≤ 300,数据组数 ≤ 5。

    题解

    • 乍一看这道题目,一个圆在一对圆中穿梭,只能相离或相切,虽然看懂了题目,但完全无从下手,就这么直接放弃了——
    • 若想做出这道题,首先不得不做的是转换题目的条件,很容易(假的)可以想到(我怎么就没想到),把每个废弃的飞船半径加上鸡腿飞船的半径,将鸡腿飞船变成一个点,现在只用看这个点能不能“离开”这片区域。
    • 只有一圈的圆把这个点包围起来了,这个点才出不去,否则都是可以的,问题就是怎么找到这“一圈”的圆。
    • 先转换坐标,以鸡腿飞船为原点,
    • 枚举两个废弃飞船,满足两个条件:在x轴同侧(在x轴上可算作在上方)且两个圆相交,那么就用并查集将这两个圆连边,
    • 这样就会出现x轴上方的一些联通块和x轴下方的一些联通块,现在需要看他们中能不能有两块把原点包围。
    • 再枚举两个圆,满足两个条件:在x轴异侧且两个圆相交,找到它们连线与x轴的交点,判断是在正半轴还是负半轴,将这两个圆所在的联通块编号之间打上标记,表示在正半轴或负半轴相交了一次,
    • 最后枚举两个联通块,如果它们之间能有连线既在正半轴相交且在负半轴相交,那么它们一定能把原点包围,则输出NO,否则输出YES。

    代码

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    using namespace std;
    #define ld long double
    #define N 310
    struct
    {
    	ld x,y,r;
    }a[N];
    int f[N],p[N][N][2];
    ld sqr(ld x)
    {
    	return x*x;
    }
    ld dis(int x,int y)
    {
    	return sqrt(sqr(a[x].x-a[y].x)+sqr(a[x].y-a[y].y));
    }
    int get(int x)
    {
    	if(f[x]==x) return x;
    	return f[x]=get(f[x]);
    }
    int main()
    {
    	int n,i,j;
    	scanf("%d",&n);
    	while(n>0)
    	{
    		for(i=1;i<=n+1;i++) scanf("%Lf%Lf%Lf",&a[i].x,&a[i].y,&a[i].r);
    		for(i=1;i<=n;i++) a[i].x-=a[n+1].x,a[i].y-=a[n+1].y,a[i].r+=a[n+1].r;
    		for(i=1;i<=n;i++) f[i]=i;
    		for(i=1;i<n;i++)
    			for(j=i+1;j<=n;j++)
    			{
    				if((a[i].y>=0)!=(a[j].y>=0)) continue;
    				if(a[i].r+a[j].r>dis(i,j))
    				{
    					int x=get(f[i]),y=get(f[j]);
    					f[x]=y;
    				}
    			}
    		memset(p,0,sizeof(p));
    		for(i=1;i<n;i++)
    			for(j=i+1;j<=n;j++)
    			{
    				if((a[i].y>=0)==(a[j].y>=0)) continue;
    				if(a[i].r+a[j].r>dis(i,j))
    				{
    					int x=get(f[i]),y=get(f[j]);
    					ld m=a[i].x;
    					if(a[i].x!=a[j].x)
    					{
    						ld k=(a[i].y-a[j].y)/(a[i].x-a[j].x),b=a[i].y-k*a[i].x;
    						m=-b/k;	
    					}
    					if(m<=0) p[x][y][1]=p[y][x][1]=1; else p[x][y][0]=p[y][x][0]=1;
    				}
    			}
    		int ok=1;
    		for(i=1;i<=n;i++)
    			for(j=1;j<=n;j++) if(p[i][j][0]&&p[i][j][1]) ok=0;
    		ok?printf("YES
    "):printf("NO
    ");
    		n=0;
    		scanf("%d",&n);
    	}
    	return 0;
    }
    
    哈哈哈哈哈哈哈哈哈哈
  • 相关阅读:
    在前后端分离的SpringBoot项目中集成Shiro权限框架
    过账销售订单装箱单报错:用库存单位数量表示的实际剩余数量不能为零
    外部系统调用AX服务
    InventSum Closed and ClosedQty
    固定资产日志过账报错
    AX批处理相关
    AX2012打开报表报错
    有折扣的销售订单过账
    AX版本查询
    AX2012 SSRS Report 相关
  • 原文地址:https://www.cnblogs.com/LZA119/p/13910051.html
Copyright © 2011-2022 走看看