poj 1418 || zoj 1696 Viva Confetti

本文探讨了一道复杂的几何问题,涉及多个圆盘的覆盖、相交及计算过程。通过求解圆与圆之间的交点,计算各部分弧长的中点,并判断这些中点是否被其他圆盘覆盖,最终确定未被遮挡的圆盘数量。文中详细阐述了解决方法及精度要求,包括使用数学公式和特定编程技巧进行实现。
摘要由CSDN通过智能技术生成

去北京前做的这个题,一直木有A。。。因为有一些情况纠结了,见下图。

黄色的盘子是第一个放的。这样的话,其他盘盘都把它的边缘给覆盖掉了,但是它依然是可见的!

这点需要处理下。

我的做法是,求圆和圆相交的交点,然后计算交点在某个圆内,按极角排序在同一个圆周上的点(记得去重),然后计算每小段弧的中点,然后看这个中点在几个圆盘里,记录这个点和对应的id(可以记成一个点一个id)。最后扫一遍中点,未被遮住的就算到答案里。

另外需要特殊处理的就是,如果一个盘盘未被覆盖,就是它是完整的,或者它完全被覆盖,这样的话计算交点是算不出来的,需要特判。

精度开12-15都没问题,开11就WA了。


#include <set>
#include <map>
#include <queue>
#include <stack>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <limits.h>
#include <string.h>
#include <string>
#include <algorithm>
#define MID(x,y) ( ( x + y ) >> 1 )
#define L(x) ( x << 1 )
#define R(x) ( x << 1 | 1 )
#define FOR(i,s,t) for(int i=(s); i<(t); i++)
#define BUG puts("here!!!")
#define STOP system("pause")
#define file_r(x) freopen(x, "r", stdin)
#define file_w(x) freopen(x, "w", stdout)

using namespace std;

const int MAX = 110;
const double eps = 1e-12;
bool dy(double x,double y)	{	return x > y + eps;}	// x > y 
bool xy(double x,double y)	{	return x < y - eps;}	// x < y 
bool dyd(double x,double y)	{ 	return x > y - eps;}	// x >= y 
bool xyd(double x,double y)	{	return x < y + eps;} 	// x <= y 
bool dd(double x,double y) 	{	return fabs( x - y ) < eps;}  // x == 
struct point{
	double x, y;
	point(){}
	point(double xx, double yy):x(xx), y(yy){}
	bool operator==(const point &a)
	{
		return dd(a.x, x) && dd(a.y, y);
	}
	void get()
	{
		scanf("%lf%lf", &x, &y);		
	}
};
double crossProduct(point a,point b,point c)//向量 ac 在 ab 的方向 顺时针是正 
{
	return (c.x - a.x)*(b.y - a.y) - (b.x - a.x)*(c.y - a.y);
}
double disp2p(point a,point b) //  a b 两点之间的距离 
{
	return sqrt( ( a.x - b.x ) * ( a.x - b.x ) + ( a.y - b.y ) * ( a.y - b.y ) );
}
double disp2p_sqr(point a,point b)
{
	return ( ( a.x - b.x ) * ( a.x - b.x ) + ( a.y - b.y ) * ( a.y - b.y ) );
}
point l2l_inst_p(point u1,point u2,point v1,point v2)
{
	point ans = u1;
	double t = ((u1.x - v1.x)*(v1.y - v2.y) - (u1.y - v1.y)*(v1.x - v2.x))/
				((u1.x - u2.x)*(v1.y - v2.y) - (u1.y - u2.y)*(v1.x - v2.x));
	ans.x += (u2.x - u1.x)*t;
	ans.y += (u2.y - u1.y)*t;
	return ans;
}
struct NODE{
	point p;
	int id;
};
struct circle{
	point c;
	double r;
	int id;
	void get()
	{
		c.get();
		scanf("%lf", &r);
	}
};
circle cir[MAX];
NODE a[MAX*MAX*2];
point p[MAX][MAX*MAX*2];
int len[MAX];

bool c2c_inst(point a,double r1,point b,double r2)
{
	if( xy(disp2p(a,b),r1+r2) && dy(disp2p(a,b),fabs(r1 - r2)) )
		return true;
	return false;
}

void l2c_inst_p(point c,double r,point l1,point l2,point &p1,point &p2)
{
	point p = c;
	double t;
	p.x += l1.y - l2.y;
	p.y += l2.x - l1.x;
	p = l2l_inst_p(p,c,l1,l2);
	t = sqrt(r*r - disp2p(p,c)*disp2p(p,c))/disp2p(l1,l2);
	p1.x = p.x + (l2.x - l1.x)*t;
	p1.y = p.y + (l2.y - l1.y)*t;
	p2.x = p.x - (l2.x - l1.x)*t;
	p2.y = p.y - (l2.y - l1.y)*t;
}
void c2c_inst_p(point c1,double r1,point c2,double r2,point &p1,point &p2)
{
	point u,v;
	double t;
	t = (1 + (r1*r1 - r2*r2)/disp2p(c1,c2)/disp2p(c1,c2))/2;
	u.x = c1.x + (c2.x - c1.x)*t;
	u.y = c1.y + (c2.y - c1.y)*t;
	v.x = u.x + c1.y - c2.y;
	v.y = u.y - c1.x + c2.x;
	l2c_inst_p(c1,r1,u,v,p1,p2);
}
point C;
bool cmp(const point& a,const point& b)  
{  
	double t1 = atan2(a.y - C.y, a.x - C.x);
	double t2 = atan2(b.y - C.y, b.x - C.x);
    if( dd(t1, t2) ) return xy(fabs(a.x),fabs(b.x));
    return xy(t1, t2);  
}
bool cmp_equal(point &a, point &b)
{
	return dd(a.x, b.x) && dd(a.y, b.y);
}
bool cmp_NODE(NODE a, NODE b)
{
	if( a.id == b.id )
	{
		if( dd(a.p.x, b.p.x) )
			return xy(a.p.y, b.p.y);
		return xy(a.p.x, b.p.x);
	}
	return a.id < b.id;
}
bool cmp_NODE_equal(NODE a, NODE b)
{
	return dd(a.p.x, b.p.x) && a.id == b.id && dd(a.p.y, b.p.y);
}
point foot_line(point a,point l1,point l2)	//ac在l1l2的逆时针方向 
{										
	point c;
    c.x = a.x - l2.y + l1.y;
    c.y = a.y + l2.x - l1.x;
	return c;	
}
bool inst[MAX];
bool see[MAX];
point getmid(point a, point b, circle &c)
{
	point mid = point((a.x+b.x)/2, (a.y+b.y)/2);
	if( mid == c.c )
		mid = foot_line(c.c, a, b);	
	point p1, p2;
	l2c_inst_p(c.c, c.r, c.c, mid, p1, p2);
	return dy(crossProduct(b, a, p1), 0) ? p2 : p1; 
}
bool c2c_ainb(point a,double r1,point b,double r2)
{
	return xyd(disp2p(a,b),r2 - r1);	//a在b中,如果是包括内切,用xyd 
}
bool check(NODE a, int n)
{
	FOR(i, a.id+1, n)
		if( xy(disp2p_sqr(a.p, cir[i].c), cir[i].r*cir[i].r) )
			return false;
	return true;
}
bool check_cover_all(circle c, int n)
{
	FOR(i, c.id+1, n)
		if( c2c_ainb(c.c, c.r, cir[i].c, cir[i].r) )
			return false;
	return true;
}
int solve(int n)
{
	int sum = 0;
	memset(inst, false, sizeof(inst));
	memset(len, 0, sizeof(len));
	FOR(i, 0, n)
	{
		FOR(k, i+1, n)
			if( c2c_inst(cir[i].c, cir[i].r, cir[k].c, cir[k].r) )
			{
				point a, b;
				inst[i] = inst[k] = true;
				c2c_inst_p(cir[i].c, cir[i].r, cir[k].c, cir[k].r, a, b);
				p[i][len[i]++] = p[k][len[k]++] = a;
				p[i][len[i]++] = p[k][len[k]++] = b;
			}
	}
	
	int l = 0;
	FOR(i, 0, n)
	{
		C = cir[i].c;
		sort(p[i], p[i]+len[i], cmp);
		len[i] = unique(p[i], p[i]+len[i], cmp_equal) - p[i];
		p[i][len[i]] = p[i][0];
		FOR(k, 0, len[i])
		{
			point t = getmid(p[i][k], p[i][k+1], cir[i]);
			a[l].p = t;
			a[l++].id = i;
			FOR(j, 0, n)
				if( xy(disp2p_sqr(t, cir[j].c), cir[j].r*cir[j].r) )
				{
					a[l].p = t;
					a[l++].id = j;
				}
		}
	}
	sort(a, a+l, cmp_NODE);
	l = unique(a, a+l, cmp_NODE_equal) - a;

	memset(see, false, sizeof(see));
	FOR(i, 0, l)
		if( check(a[i], n) )
			see[a[i].id] = true;

	FOR(i, 0, n)
	{
		if( see[i] )
		{
			sum++;
			continue;
		}
		if( !inst[i] && check_cover_all(cir[i], n) )
			sum++;
	}
	return sum;
}
int main()
{
	int n;

	while( ~scanf("%d", &n) && n )
	{
		FOR(i, 0, n)
		{
			cir[i].get();
			cir[i].id = i;
		}
		int ans = solve( n );
		printf("%d\n", ans);
	}

return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值