洛谷B2031 计算三角形面积 题解
洛谷B2031 计算三角形面积 题解
题目链接:B2031 计算三角形面积
题目描述:
平面上有一个三角形,它的三个顶点坐标分别为 \((x_1,y_1),(x_2,y_2),(x_3,y_3)\),那么请问这个三角形的面积是多少。
输入格式:
输入仅一行,包括 \(6\) 个双精度浮点数,分别对应 \(x_1,y_1,x_2,y_2,x_3,y_3\)。坐标的绝对值不超过 \(100\),且小数点后最多只有一位。
输出格式:
输出也是一行,输出三角形的面积,精确到小数点后两位。
常规的有两种做法:海伦公式、向量叉积。
时间复杂度都是 \(O(1)\) ,不过向量叉积计算的话精度明显会更高,代码也更简单。
海伦公式:
记三角形的边长为 \(a,b,c\) (可通过两点距离公式计算),则 \[ \begin{array}{} S=\sqrt{s(s-a)(s-b)(s-c)}&\text{where }s=\dfrac{a+b+c}{2} \end{array} \] 向量叉积:
不妨记三个点为 \(A,B,C\) ,并记 \(\mathbf{a}=\overrightarrow{AB},~\mathbf{b}=\overrightarrow{BC},~\vartheta\) 为 \(\mathbf{a}\) 向 \(\mathbf{b}\) 的旋转角,那么 \[ \begin{aligned} S_{\triangle ABC}&=\frac{1}{2}\cdot|\mathbf{a}\times\mathbf{b}| \\[6pt]&=\frac{1}{2}\cdot\left||\mathbf{a}||\mathbf{b}|\sin \vartheta\right| \end{aligned} \] 其中向量的模可以直接用两点距离公式算,而 \(\sin \vartheta\) 可以通过和差角公式计算。
记 \(\mathbf{a}\) 的极角为 \(\vartheta_1\) ,\(\mathbf{b}\) 的极角为 \(\vartheta_2\) ,根据定义有 \[ \begin{aligned} \sin \vartheta &= \sin (\vartheta_2-\vartheta_1) \\[6pt] &= \sin \vartheta_2 \cos \vartheta_1 - \cos\vartheta_2 \sin \vartheta_1 \end{aligned} \] 记 \(\mathbf{a}=(x_a,y_a),~\mathbf{b}=(x_b,y_b)\) ,代入可以发现 \[ \begin{aligned} S_{\triangle ABC}&=\frac{1}{2}\cdot\left||\mathbf{a}||\mathbf{b}| (\sin \vartheta_2 \cos \vartheta_1 - \cos\vartheta_2 \sin \vartheta_1)\right| \\[6pt]&=\frac{1}{2}|x_ay_b-x_by_a| \end{aligned} \] 当然如果各位熟悉这个推导过程的话,直接就能得到答案了。
用海伦公式的代码(不推荐):
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
template<typename T> void up(T &x, T y) { x < y ? x = y : 0; }
template<typename T> void down(T &x, T y) { x > y ? x = y : 0; }
#define rep(i, a, b) for(int i = (a), i##END = (b); i <= i##END; i++)
#define Rep(i, a, b) for(int i = (a), i##END = (b); i >= i##END; i--)
#define N ((int)())
double x[5], y[5];
double dis(double x1, double y1, double x2, double y2)
{
return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
// freopen("check.in","r",stdin);
// freopen("check.out","w",stdout);
rep(i, 0, 2) cin >> x[i] >> y[i];
const double a = dis(x[0], y[0], x[1], y[1]);
const double b = dis(x[1], y[1], x[2], y[2]);
const double c = dis(x[2], y[2], x[0], y[0]);
const double s = (a + b + c) / 2.0;
cout << fixed << setprecision(2);
cout << sqrt(s * (s - a) * (s - b) * (s - c)) << '\n';
return 0;
}
用叉积计算的代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
template<typename T> void up(T &x, T y) { x < y ? x = y : 0; }
template<typename T> void down(T &x, T y) { x > y ? x = y : 0; }
#define rep(i, a, b) for(int i = (a), i##END = (b); i <= i##END; i++)
#define Rep(i, a, b) for(int i = (a), i##END = (b); i >= i##END; i--)
#define N ((int)())
double x[5], y[5];
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
// freopen("check.in","r",stdin);
// freopen("check.out","w",stdout);
rep(i, 0, 2) cin >> x[i] >> y[i];
const double x1 = x[1] - x[0], y1 = y[1] - y[0];
const double x2 = x[2] - x[0], y2 = y[2] - y[0];
cout << fixed << setprecision(2) << abs((x1 * y2 - x2 * y1) / 2.0) << '\n';
return 0;
}




