文章目录
POJ 2284-That Nice Euler Circuit
题意:给你一个可能会自交的多边形,问平面被分成了几份。
题解:计算几何 欧拉定理应用
思路:
-
我们要求点数和边数,点数可以求交点,然后排序去重。
-
边数的话,对于一条线段,其内部(不包括端点)每增加一个点,这个线段的贡献就会加一。
-
因此可以枚举每条原始边,枚举所有点,判断是否可以分割线段。
AC代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;
const int N=100100;
typedef long long LL;
int n;
const double eps = 1e-8;
int sign(double x){
if(fabs(x) < eps) return 0;
if(x < 0) return -1;
return 1;
}
int dcmp(double x, double y){
if(fabs(x - y) < eps) return 0;
if(x < y) return -1;
return 1;
}
struct point{
double x,y;
bool operator < (const point a)const{
if(dcmp(x, a.x)) return x < a.x;
return y < a.y;
}
bool operator == (const point a) const{ return !dcmp(x, a.x) && !dcmp(y, a.y); }
};
point operator + (point a,point b) { return {a.x + b.x, a.y + b.y};}
point operator - (point a,point b) { return {a.x - b.x, a.y - b.y};}
point operator * (point a,double b) { return {a.x * b, a.y * b};}
double cross(point a,point b) { return a.x * b.y - a.y * b.x; }
double dot(point a,point b) { return a.x * b.x + a.y * b.y; }
double area(point a,point b,point c) { return cross(b - a,c - a)/2; }
bool segment_intersection(point a1, point a2, point b1, point b2){//判断两个线段是否只有一个交点
if(sign(cross(a2 - a1, b2 - b1))==0) return 0;
double c1 = cross(a2 - a1, b1 - a1), c2 = cross(a2 - a1, b2 - a1);
double c3 = cross(b2 - b1, a2 - b1), c4 = cross(b2 - b1, a1 - b1);
return sign(c1) * sign(c2) <= 0 && sign(c3) * sign(c4) <= 0;
}
point get_line_intersection(point p, point v, point q, point w){
point u = p - q;
double t = cross(w, u) / cross(v, w);
return p + v * t;
}
bool on_segment(point p, point a1, point a2){
return !sign(cross(a1 - p, a2 - p)) && sign(dot(a1 - p, a2 - p)) < 0;
}
point P[N],q[N];
int cnt;
int main()
{
int _ = 1;
while(scanf("%d",&n)!=EOF)
{
cnt = 0;
if(!n) break;
for(int i=0; i< n;i ++)
{
scanf("%lf %lf",&P[i].x, &P[i].y);
q[cnt++] = P[i];
}
n --;
for(int i=0; i<n; i++)
for(int j=i + 1; j < n; j++)
if(segment_intersection(P[i], P[i + 1], P[j], P[j + 1]))
q[cnt++] = get_line_intersection(P[i], P[i + 1] - P[i], P[j], P[j + 1] - P[j]);
sort(q, q + cnt);
LL pos = unique(q, q + cnt) - q;
LL e = n;
for(int i=0; i<n; i++)
for(int j=0; j<pos; j++)
if(on_segment(q[j], P[i], P[i + 1])) e++;
printf("Case %d: There are %lld pieces.\n", _++, 2 + e - pos);
}
// system("pause");
return 0;
}
圆(circle)
题解:计算几何 欧拉定理应用
思路:
- 研究一个圆的内接四边形,我们发现,一个内接四边形会多贡献一个交点,而且对于其两条对角线,都会被多贡献的那个交点分为两半。因此,一个内接四边形会多贡献一个交点 和 两条线段。
AC代码:
#include<iostream>
#include<cstdio>
using namespace std;
const int N=1e5+10;
typedef long long LL;
int main()
{
LL n;
// v = n + C(4,n) , e = n + C(2,n) + 2 * C(4,n)
while(cin>>n)
{
cout<<1 + n * (n - 1) /2 + n * (n - 1) * (n - 2) * (n - 3) / 24<<endl;
}
system("pause");
return 0;
}
Codeforces 933C C. A Colourful Prospect
题意:给你平面上的 n n n 个圆,问平面被分成了几份。
题解:Codeforces 933C+D C. A Colourful Prospect D. A Creative Cutout
思路:和第一题一样,求交点、去重、判断是否在圆上。注意两圆重合的情况。
AC代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;
const int N=100100;
typedef long long LL;
const double eps = 1e-8;
int sign(double x){
if(fabs(x) < eps) return 0;
if(x < 0) return -1;
return 1;
}
int dcmp(double x, double y){
if(fabs(x - y) < eps) return 0;
if(x < y) return -1;
return 1;
}
struct point{
double x,y;
bool operator < (const point a)const{
if(dcmp(x, a.x)) return x < a.x;
return y < a.y;
}
bool operator == (const point a) const{ return !dcmp(x, a.x) && !dcmp(y, a.y); }
};
point operator + (point a,point b) { return {a.x + b.x, a.y + b.y};}
point operator - (point a,point b) { return {a.x - b.x, a.y - b.y};}
point operator * (point a,double b) { return {a.x * b, a.y * b};}
point operator / (point a,double b) { return {a.x / b, a.y / b};}
double cross(point a,point b) { return a.x * b.y - a.y * b.x; }
double dot(point a,point b) { return a.x * b.x + a.y * b.y; }
double area(point a,point b,point c) { return cross(b - a,c - a)/2; }
double length(point a) { return sqrt(a.x * a.x + a.y * a.y); }
point norm(point a) { return a / length(a); }
point rotate(point a,double rad) { return {a.x * cos(rad) -a.y * sin(rad), a.x * sin(rad) + a.y * cos(rad)}; }
bool segment_intersection(point a1, point a2, point b1, point b2){//判断两个线段是否只有一个交点
if(sign(cross(a2 - a1, b2 - b1))==0) return 0;
double c1 = cross(a2 - a1, b1 - a1), c2 = cross(a2 - a1, b2 - a1);
double c3 = cross(b2 - b1, a2 - b1), c4 = cross(b2 - b1, a1 - b1);
return sign(c1) * sign(c2) <= 0 && sign(c3) * sign(c4) <= 0;
}
point get_line_intersection(point p, point v, point q, point w){
point u = p - q;
double t = cross(w, u) / cross(v, w);
return p + v * t;
}
bool on_segment(point p, point a1, point a2){
return !sign(cross(a1 - p, a2 - p)) && sign(dot(a1 - p, a2 - p)) < 0;
}
double get_dis(point a, point b) { return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); }
int n;
point P[3],q[20];
int cnt;
double r[3];
int pa[3];
int sum[3];
int find(int x)
{
if(pa[x]==-1) return x;
return pa[x] == find(pa[x]);
}
void join(int a,int b)
{
int xr = find(a), yr = find(b);
if(xr!=yr) pa[xr] = yr;
}
int main()
{
scanf("%d",&n);
for(int i=0; i<n; i++)
{
scanf("%lf %lf %lf",&P[i].x, &P[i].y, &r[i]);
P[i].x *=10000; P[i].y *=10000; r[i] *= 10000;
}
pa[0]=pa[1]=pa[2] = -1;
int c = 0;
for(int i=0; i<n; i++)
for(int j=i + 1; j<n; j++)
{
double dis = get_dis(P[i], P[j]);
if(dcmp(fabs(r[i] - r[j]), dis) <= 0 && dcmp(r[i] + r[j], dis) >= 0 && !(P[i] == P[j] && !dcmp(r[i], r[j])))
{
join(i, j);
double rad = (r[i] * r[i] + dis * dis - r[j] * r[j]) / (2 * r[i] * dis);
if(rad < -1) rad = -1;
if(rad > 1 ) rad = 1;
rad = acos(rad);
q[cnt++] = P[i] + norm(rotate(P[j] - P[i], rad)) * r[i];
q[cnt++] = P[i] + norm(rotate(P[j] - P[i], -rad)) * r[i];
}
}
for(int i=0; i<n; i++) if(pa[i] == -1) c ++;
sort(q, q + cnt);
int pos = unique(q, q + cnt) - q;
if(!cnt) pos = 0;
for(int i=0; i < n; i++)
for(int j=0; j<pos; j++)
if(!dcmp(r[i], get_dis(P[i], q[j]))) sum[i]++;
int e = 0, v = pos;
for(int i=0; i<n; i++)
if(!sum[i]) e++, v++;
else e += sum[i];
printf("%d\n",c + 1 + e - v);
// cout<<c<<" "<<e<<" "<<v;
// system("pause");
return 0;
}