定理:设G为任意的连通的平面图,则v-e+f=2,v是G的顶点数,e是G的边数,f是G的面数。
题目描述:给出一个一笔画图形的n个节点的坐标,请你求解这个图形把平面分成了几个面
一笔画图形一个是把图上所有的边仅且遍历一次的封闭连通图。
分析:求面的问题就分解为求顶点个数与边条数的问题。
点的求法:遍历每条线段,如果是规范相交,则将该点存入V[]数组中。最后对V[]数组进行排序,使用STL中的unique()函数对求出来的交点进行去重处理。
边的求法:遍历每个交点和每条线段,如果交点在线段上,边数加一
//欧拉定理
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string.h>
#include <vector>
using namespace std;
struct point
{
double x, y;
point(double x = 0.0, double y = 0.0) :x(x), y(y) {};
};
typedef point Vector;
const double eps = 1e-8;
//判断double类型(x)与0的大小
int dcmp(double x) { if (fabs(x)<eps) return 0; return (x<0) ? -1 : 1; }
//向量的运算符重载
Vector operator + (Vector A, Vector B) { return Vector(A.x + B.y, A.y + B.y); }
Vector operator - (Vector A, Vector B) { return Vector(A.x - B.y, A.y - B.y); }
Vector operator * (Vector A, double p) { return Vector(p * A.x, p * A.y); }
Vector operator / (Vector A, double p) { return Vector(A.x / p, A.y / p); }
bool operator < (const point& a, const point& b) {//判断a点是否小于b点
return a.x < b.x || (a.x == b.x && a.y < b.y);
}
bool operator == (const point& a, const point &b) {//判断两个点是否相等
return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0;
}
//向量的运算
double Dot(Vector A, Vector B) { return A.x * B.x + A.y * B.y; }//向量的点乘
double Cross(Vector A, Vector B) { return A.x * B.y - A.y * B.x; }//向量的叉积
//判断规范相交
bool SegmentProperIntersection(point a1, point a2, point b1, point b2)
{
double c1 = Cross(a2 - a1, b1 - a1), c2 = Cross(a2 - a1, b2 - a1);
double c3 = Cross(b2 - b1, a1 - b1), c4 = Cross(b2 - b1, a2 - b1);
return dcmp(c1)*dcmp(c2)<0 && dcmp(c3)*dcmp(c4)<0;
}
//两直线交点(参数法)
point GetLineIntersection(point P, Vector v, point Q, Vector w)
{
Vector u = P - Q;
double t = Cross(w, u) / Cross(v, w);
return P + v*t;
}
//判断点p是否在线段a1a2上(叉乘=0;点乘<0)
bool OnSegment(point p, point a1, point a2)
{
return dcmp(Cross(a1 - p, a2 - p)) == 0 && dcmp(Dot(a1 - p, a2 - p))<0;
}
const int maxn = 300 + 10;
point P[maxn], V[maxn * maxn];
int main()
{
int n, kase = 0, c, e;
while (~scanf("%d", &n) && n) {
for (int i = 0; i < n; i++) {
scanf("%d%d", &P[i].x, &P[i].y);
V[i] = P[i];
}
c = n - 1; e = n - 1;
for (int i = 0; i < c; i++)//遍历每个点
for (int j = i + 1; j < c; j++)
if (SegmentProperIntersection(P[i], P[i + 1], P[j], P[j + 1]))//如果是规范相交
V[c++] = GetLineIntersection(P[i], P[i + 1] - P[i], P[j], P[j + 1] - P[j]);//把交点存入V[]中
sort(V, V + c);
c = unique(V, V + c) - V;//把重复元素放到数组后面,c为(去重后)交点的个数
for (int i = 0; i < c; i++)//遍历每个交点
for (int j = 0; j < n - 1; j++)//遍历每条线段
if (OnSegment(V[i], P[j], P[j + 1])) e++;//如果交点在线段上,边数加一
printf("Case %d: There are %d pieces.\n", ++kase, e + 2 - c);
}
}

6216





