数学杂谈(算法类+ Ancient Berland Circus的解决)

这个随笔是算是我博客数学类的第一条吧,觉得还是写点感想的好。话说这个算法里的数学类一般就是解决一些容斥呀,数论呀,或者是组合数学之类的问题。但老实说,这只是狭义上的数学,但我们用什么数据结构啊,什么dp呀,什么图论呀,都应归属于广义上的数学。所以,无论是谁,都应该将数学作为自己的最强辅助。对于理论性的东西,很多acmer都不愿去思考,都只会拿一些现成的东西直接套用,虽说这是一种处理问题的技巧,但若长此以往,肯定会对我们思维能力造成坏的影响。所以,我们遇到问题一定要独立思考,少用别人的套路,多点自己的套路。

好吧,废话讲了那么多,我们来讨论讨论关于欧几里德这个小东西。欧几里德算法又称辗转相除法,是指用于计算两个正整数a,b的最大公约数。哦,是不是觉得这个很简单?你看到这个一定毫不犹豫写上下面这个代码

1 int gcd(int a, int b) {
2     return a ? gcd(b%a, a) : b;
3 }

嗯,是很简单,但是注意,欧几里德只能解决两个整数的最大公约数的问题,但小数(当然,小数并没有最大公约数这个概念,这里都统一将小数看作整数)呢?小数电脑可不支持取模运算呀。嗯,没错,我们一直用电脑自带的取模运算符%来帮我们进行取模运算,但很多学生(包括我T_T)一开始就接触这个导致它的老祖宗没用上过,其实很简单,对任意非0数取模(当然小数也不存在取模这个东西,我们类比就行),我们其实可以统一这么算

1 double MOD(double a, double b) { // a % b
2     return a - floor(a / b) * b;
3 }

既然mod可以这样算,那么小数的gcd运算我们就可以得出

1 #define esp 1e-4
2 
3 double Decimal_gcd(double a, double b) {
4     return a >= esp ? Decimal_gcd(b - floor(b/a)*a, a) : b;
5 }

好,讲到这了,我们就来实战演练

http://codeforces.com/contest/1/problem/C

这道题就是小数最大公约数的经典例子,大家可以去尝试一下。

下面是我的答案

 1 #include<bits/stdc++.h>
 2 #define eps 1e-4
 3 #define pie acos(-1.0)
 4 #define pows(x) ((x)*(x))
 5 
 6 using namespace std;
 7 typedef double intd;
 8 
 9 intd e[3], tri[3];
10 
11 intd dis(intd x1,intd y1,intd x2,intd y2) { //计算边长 
12     return sqrt(pows(x2-x1)+pows(y2-y1));
13 }
14 
15 intd gettri(int i) { //得到边i所对应的圆心角,余弦定理 
16     intd s=0.0,m=2.0;
17     for(int j=0;j<3;j++) if(i!=j)
18         s += e[j] * e[j], m *= e[j];
19     intd temp = (s - e[i]*e[i])/m;
20     return acos(temp);
21 }
22 
23 intd gcd(double a, double b) {
24     return a >= eps ? gcd(b - floor(b/a)*a, a) : b;
25 }
26 
27 int main() {
28     intd a[3], b[3];
29     for(int i=0;i<3;i++)
30         scanf("%lf%lf", &a[i], &b[i]);
31     
32     int cn = 0;
33     for(int i=0;i<3;i++)
34         for(int j=i+1;j<3;j++)
35             e[cn++] = dis(a[i],b[i],a[j],b[j]); //得到三边 
36     
37     for(int i=0;i<3;i++)
38         tri[i] = gettri(i);
39     
40     intd g = gcd(tri[0], gcd(tri[1], tri[2]));
41     intd R = e[0]/(2.0*sin(tri[0]));
42     
43     g *= 2.0;
44     printf("%.6f\n", 2.0*pie/g * pows(R)*sin(g)/2.0);
45     return 0;
46 }

 

posted @ 2017-10-06 11:08  UtopioSPH  阅读(331)  评论(0编辑  收藏  举报