您的位置:首页 > 产品设计 > UI/UE

[代码]ural 1913 Titan Ruins: Old Generators Are Fine Too

2012-10-22 20:21 309 查看

Abstract

ural 1913 Titan Ruins: Old Generators Are Fine Too

implementation 几何 圆交

Source

http://acm.timus.ru/problem.aspx?space=1&num=1913

Solution

主要思路就是判断距离到某两个点是r,另一个点是2r的点。

比赛时候用三分乱搞,大概是被卡了精度还是什么的,没有通过。

赛后用圆交重写了一遍,一开始还是没通过。

然后发现自己的圆交模板是针对面积问题的,单点的情况没有考虑清楚,乱改的时候改错了。大致就是处理圆覆盖的情况时,在预处理统计时算被覆盖了一次,在算两圆交点的时候又被统计了一次。还是没弄熟悉圆交的原理所致。

Code

#include <iostream>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const double EPS = 1e-8;
const double PI = acos(-1.0);

inline int sgn(double x) {
if (fabs(x)<EPS) return 0;
return x>0?1:-1;
}

struct sp {
double x, y;
double pa;
int cnt;
sp() {}
sp(double a, double b): x(a), y(b) {}
sp(double a, double b, double c, int d): x(a), y(b), pa(c), cnt(d) {}
bool operator<(const sp &rhs) const {
if (sgn(pa-rhs.pa)==0) return cnt>rhs.cnt;
return pa<rhs.pa;
}
void read() {scanf("%lf%lf", &x, &y);}
void write() {printf("%.10f %.10f\n", x, y);}
}t, s1, s2, p[5], e[20];
double r, rad[5];
int cover[5];

sp operator*(double d, const sp &v) {
return sp(d*v.x, d*v.y);
}

sp operator-(const sp &u, const sp &v) {
return sp(u.x-v.x, u.y-v.y);
}

sp operator+(const sp &u, const sp &v) {
return sp(u.x+v.x, u.y+v.y);
}

double dot(const sp &u, const sp &v) {
return u.x*v.x+u.y*v.y;
}

double det(const sp &u, const sp &v) {
return u.x*v.y-u.y*v.x;
}

double dis(const sp &u, const sp &v) {
double dx = u.x-v.x;
double dy = u.y-v.y;
return sqrt(dx*dx+dy*dy);
}

double dissqr(const sp &u, const sp &v) {
double dx = u.x-v.x;
double dy = u.y-v.y;
return dx*dx+dy*dy;
}

void write(sp u, sp v) {
puts("Now we have enough power");
u.write(); v.write();
}

bool cirint(const sp &u, double ru, const sp &v, double rv, sp &a, sp &b) {
double d = dis(u, v);
if (sgn(d-(ru+rv))>0 || sgn(d-fabs(ru-rv))<=0) return 0;
sp c = u-v;
double ca, sa, cb, sb, csum, ssum;

ca = c.x/d, sa = c.y/d;
cb = (rv*rv+d*d-ru*ru)/(2*rv*d), sb = sqrt(1-cb*cb);
csum = ca*cb-sa*sb;
ssum = sa*cb+sb*ca;
a = sp(rv*csum, rv*ssum);
a = a+v;

sb = -sb;
csum = ca*cb-sa*sb;
ssum = sa*cb+sb*ca;
b = sp(rv*csum, rv*ssum);
b = b+v;

return 1;
}

bool cu(int N, sp p[], double r[], sp &res) {
int i, j, k;
memset(cover, 0, sizeof cover);
for (i = 0; i < N; ++i)
for (j = 0; j < N; ++j) {
double rd = r[i]-r[j];
if (i!=j && sgn(rd)>0 && sgn(dis(p[i], p[j])-rd)<=0)
cover[j]++;
}
sp a, b;
for (i = 0; i < N; ++i) {
int ecnt = 0;
e[ecnt++] = sp(p[i].x-r[i], p[i].y, -PI, 1);
e[ecnt++] = sp(p[i].x-r[i], p[i].y, PI, -1);
for (j = 0; j < N; ++j) {
if (j==i) continue;
if (cirint(p[i], r[i], p[j], r[j], a, b)) {
e[ecnt++] = sp(a.x, a.y, atan2(a.y-p[i].y, a.x-p[i].x), 1);
e[ecnt++] = sp(b.x, b.y, atan2(b.y-p[i].y, b.x-p[i].x), -1);
if (sgn(e[ecnt-2].pa-e[ecnt-1].pa)>0) {
e[0].cnt++;
e[1].cnt--;
}
}
}
sort(e, e+ecnt);
int cnt = e[0].cnt;
for (j = 1; j < ecnt; ++j) {
if (cover[i]+cnt==N) {
double a = (e[j].pa+e[j-1].pa)/2;
res = p[i]+sp(r[i]*cos(a), r[i]*sin(a));
return 1;
}
cnt += e[j].cnt;
}
}
return 0;
}

bool solve(const sp &o, const sp &u, const sp &v, double r) {
p[0] = o, rad[0] = r+r;
p[1] = u; p[2] = v; rad[1] = rad[2] = r;
sp a, b;
if (cu(3, p, rad, a)) {
b = 0.5*(a-o);
b = o+b;
write(a, b);
return 1;
}
else return 0;
}

int main() {
cin>>r;
t.read(); s1.read(); s2.read();
sp a, b, c, d;
if (cirint(s1, r, s2, r, a, b)) {
if (solve(t, s1, s2, r)) return 0;
}
else {
if (cirint(s1, r, t, r, a, b) && cirint(s2, r, t, r, c, d)) {
write(a, c);
return 0;
}
else {
if (solve(s1, t, s2, r)) return 0;
if (solve(s2, t, s1, r)) return 0;
}
}
puts("Death");
return 0;
}


顺便贴圆交模板,这回的应该没问题了。

#include <cmath>
#include <algorithm>
using namespace std;

const double PI = acos(-1.0);
const double EPS = 1e-8;

int sgn(double d) {
if (fabs(d)<EPS) return 0;
return d>0?1:-1;
}

struct sp {
double x, y;
double pa;
int cnt;
sp() {}
sp(double a, double b): x(a), y(b) {}
sp(double a, double b, double c, int d): x(a), y(b), pa(c), cnt(d) {}
bool operator<(const sp &rhs) const {
/* 需要处理单点的情况时
if (sgn(pa-rhs.pa)==0) return cnt>rhs.cnt;
*/
return pa<rhs.pa;
}
void read() {scanf("%lf%lf", &x, &y);}
void write() {printf("%lf %lf\n", x, y);}
};

sp operator+(const sp &u, const sp &v) {
return sp(u.x+v.x, u.y+v.y);
}

sp operator-(const sp &u, const sp &v) {
return sp(u.x-v.x, u.y-v.y);
}

double det(const sp &u, const sp &v) {
return u.x*v.y-v.x*u.y;
}

double dir(const sp &p, const sp &u, const sp &v) {
return det(u-p, v-p);
}

double dis(const sp &u, const sp &v) {
double dx = u.x-v.x;
double dy = u.y-v.y;
return sqrt(dx*dx+dy*dy);
}

//计算两圆交点
//输入圆心坐标和半径
//返回两圆是否相交(相切不算)
//如果相交,交点返回在a和b(从a到b为u的交弧)
bool cirint(const sp &u, double ru, const sp &v, double rv, sp &a, sp &b) {
double d = dis(u, v);
/* 需要处理单点的情况时 覆盖的情况在这里不统计
if (sgn(d-(ru+rv))>0 || sgn(d-fabs(ru-rv))<=0) return 0;
*/
if (sgn(d-(ru+rv))>=0 || sgn(d-fabs(ru-rv))<=0) return 0;
sp c = u-v;
double ca, sa, cb, sb, csum, ssum;

ca = c.x/d, sa = c.y/d;
cb = (rv*rv+d*d-ru*ru)/(2*rv*d), sb = sqrt(1-cb*cb);
csum = ca*cb-sa*sb;
ssum = sa*cb+sb*ca;
a = sp(rv*csum, rv*ssum);
a = a+v;

sb = -sb;
csum = ca*cb-sa*sb;
ssum = sa*cb+sb*ca;
b = sp(rv*csum, rv*ssum);
b = b+v;

return 1;
}

sp e[222];
int cover[111];

//求圆并
//输入点数N,圆心数组p,半径数组r,答案数组s
//s[i]表示被至少i个圆覆盖的面积(最普通的圆并就是s[1])
void circle_union(int N, sp p[], double r[], double s[]) {
int i, j, k;
memset(cover, 0, sizeof cover);
for (i = 0; i < N; ++i)
for (j = 0; j < N; ++j) {
double rd = r[i]-r[j];
//覆盖的情况在这里统计
if (i!=j && sgn(rd)>0 && sgn(dis(p[i], p[j])-rd)<=0)
cover[j]++;
}
for (i = 0; i < N; ++i) {
int ecnt = 0;
e[ecnt++] = sp(p[i].x-r[i], p[i].y, -PI, 1);
e[ecnt++] = sp(p[i].x-r[i], p[i].y, PI, -1);
for (j = 0; j < N; ++j) {
if (j==i) continue;
if (cirint(p[i], r[i], p[j], r[j], a, b)) {
e[ecnt++] = sp(a.x, a.y, atan2(a.y-p[i].y, a.x-p[i].x), 1);
e[ecnt++] = sp(b.x, b.y, atan2(b.y-p[i].y, b.x-p[i].x), -1);
if (sgn(e[ecnt-2].pa-e[ecnt-1].pa)>0) {
e[0].cnt++;
e[1].cnt--;
}
}
}
sort(e, e+ecnt);
int cnt = e[0].cnt;
for (j = 1; j < ecnt; ++j) {
double pad = e[j].pa-e[j-1].pa;
s[cover[i]+cnt] += (det(e[j-1], e[j])+r[i]*r[i]*(pad-sin(pad)))/2;
cnt += e[j].cnt;
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐