编程之美笔记


1. 点是否在三角形内

解法1:如果点在三角形内部,该点和另外的三个点所组成的三个三角形的面积之和和原三角形的面积相等。


#include <iostream>
#include <cmath>

using namespace std;

struct point
{
    double x;
    double y;
};

bool Compare(double a, double b)
{
    if((a - b > -0.00001)&& (a - b < 0.00001))
    {
        return true;
    }
    else
    {
        return false;
    }
}

void Compute( point A, point B, point C, double &a, double &b, double &c)
{
    a = sqrt( (A.x-B.x)*(A.x-B.x) + (A.y-B.y)*(A.y-B.y));
    b = sqrt( (B.x-C.x)*(B.x-C.x) + (B.y-C.y)*(B.y-C.y));
    c = sqrt( (C.x-A.x)*(C.x-A.x) + (C.y-A.y)*(C.y-A.y));
}

double Area( point A, point B, point C)
{
    double a=0, b=0, c = 0;
    Compute(A, B, C, a, b, c);
    double p = (a+b+c) / 2;
    return sqrt((p-a)*(p-b)*(p-c)*p);
}

bool isInTriangle( point A, point B, point C, point D)
{
    return Compare( Area(A, B, D) + Area(A, C, D) + Area( B, C, D), Area( A, B, C));
}

int main()
{
    point A, B, C, D;

    A.x = 0;
    A.y = 0;
    B.x = 5;
    B.y = 0;
    C.x = 0;
    C.y = 5;
    D.x = 1;
    D.y = 1;

    if( isInTriangle( A, B, C, D))
    {
        cout << "In Triangle" << endl;
    }

    return 0;
}

方法二:使用向量内积的正负来判断,如果点D位于三角形内部,那么D位于AB,BC,CA的左边,位于左边时,AB,AD向量叉积为正,在右边则为负,在一条直线上则为0。


        

#include <iostream>
#include <cmath>

using namespace std;

struct point
{
    double x;
    double y;
};

double Product(point A, point B, point C)
{
    return (B.x-A.x)*(C.y - A.y) - (C.x-A.x)*(B.y-A.y);
}

bool isInTriangle( point A, point B, point C, point D)
{
    if(Product(A, B, C) >= 0 && Product(B, C, D) >= 0 && Product(C, A, D) >= 0)
    {
        return true;
    }

    return false;
}

int main()
{
    point A, B, C, D;

    A.x = 0;
    A.y = 0;
    B.x = 5;
    B.y = 0;
    C.x = 0;
    C.y = 5;
    D.x = 1;
    D.y = 1;

    if( isInTriangle( A, B, C, D))
    {
        cout << "In Triangle" << endl;
    }

    return 0;
}

2. 只考加法的题目

         本题只用到加法,别嫌题目简单,不妨试试看。

         我们知道:

                  1 + 2 = 3;

                  4 + 5 = 9;

                  2 + 3 + 4 = 9;

         等式的左边都是两个或两个以上的连续的自然数相加,那么是不是所有的整数都可以写成这样的形式呢?稍微考虑一下,我们发现,4、8等数并不能写成这的形式。

         问题1:写一个程序,对于一个64位正整数,输出它所有的可能的连续自然数(两个以上)之和的算式?

         使用暴力的方法:

         从1到N/2之间的数字,进行循环,使用两个索引下标变量,查找是不是可以写成多个数字的和:       

#include <iostream>
#include <cmath>

using namespace std;

int PrintSum( int n)
{
    int ret = 1;

    int start = 1, end = 2;
    int sum = start + end;
    while( start < n / 2)
    {
        if( sum < n)
        {
            end++;
            sum += end;
        }
        else if( sum > n)
        {
            sum -= start;
            start++;
        }

        if( sum == n)
        {
            ret = 0;
            cout << sum << " = ";
            for( int i = start; i < end; i++)
            {
                cout << i << " + ";
            }
            cout << end << ";" << endl;

            end++;
            sum += end;
        }
    }

    return ret;
}

int main()
{

    if(PrintSum(1000) == 1)
    {
        cout << "No sum exist" << endl;
    }

    return 0;
}

         问题2:大家在测试上面程序的过程中,肯定会注意到有一些数字不能表达为一系列的连续的自然数之和,例如32好像就找不到。那么,这样的数字有什么规律呢,能否证明你的结论?

         对于判断是否一个数字可以被按照问题1的方法进行拆分,总结如下规律:

         对于可以拆分的数字满足如下条件:

         拆分为两个数字:x + (x+1) = 2x + 1         或 x-1 + x = 2x - 1 = 2(x-1) + 1

         三个数字: x + (x+1)  + (x+2) = 3x + 3 = 3(x+1)       (x -1) + x + (x+1) = 3x       (x - 2) + (x-1)  + x = 3x - 3 = 3(x-1)

         四个数字: x + (x+1)  + (x+2) + (x+3) = 4x + 6 = 4(x+1)  + 2      (x -1) + x + (x+1) + (x+2) = 4x + 2       (x - 2) + (x-1)  + x + (x+1) = 4x - 2 = 4(x-1) + 2    (x - 3) + (x-2)  + (x - 1) + x = 4x - 6 = 4(x-2) + 2

         五个数字: x + (x+1)  + (x+2) + (x+3) + (x+4) = 5x + 10 = 5(x+2)      (x -1) + x + (x+1) + (x+2) + (x+3) = 5x + 5 = 5(x + 1)     (x - 2) + (x-1)  + x + (x+1) + (x+2) = 5x      (x - 3) + (x-2)  + (x - 1) + x + (x + 1) = 5x - 5 = 5(x-1)        (x - 4) + (x - 3) + (x-2)  + (x - 1) + x  = 5x - 10 = 5(x-2)

         六个数字: x + (x+1)  + (x+2) + (x+3) + (x+4) + (x+5) = 6x + 15 = 6(x+2) + 3      (x -1) + x + (x+1) + (x+2) + (x+3) + (x+4) = 6x + 10 = 6(x + 1) +3     (x - 2) + (x-1)  + x + (x+1) + (x+2) + (x+3) = 6x + 3      (x - 3) + (x-2)  + (x - 1) + x + (x + 1)  + (x + 2) = 6(x - 1) + 3        (x - 4) + (x - 3) + (x-2)  + (x - 1) + x + (x + 1) = 6x - 9 = 6(x-2) + 3      (x - 5) +  (x - 4) + (x - 3) + (x-2)  + (x - 1) + x = 6x - 15 = 6(x-3) + 3
         。。。。。。
         从上面的总结中,可以得出一个结论,如果一个数字可以被分解为已连续数字的和,则其符合如下的规律:

         对于可以拆分为奇数个连续数字和的情况: N % k == 0    拆分为偶数个连续数字和的情况: N  % k == k  / 2   (k为偶数)

         其中N为待拆分数字,k为欲拆分成的数字数

#include <iostream>
#include <cmath>

using namespace std;
bool CanBeDecomposed( int n)
{
    int i = 2;
    int sum = i*(i + 1) / 2;
    while(sum < n)
    {
        if((i & 1) == 1) // 奇数
        {
            if( n % i == 0)
            {
                return true;
            }
        }
        else    // 偶数
        {
            if( n % i == i / 2)
            {
                return true;
            }
        }

        ++i;
        sum = i*(i + 1) / 2;
    }

    return false;
}

int main()
{
    if( CanBeDecomposed( 10000))
    {
        cout << "10000 can be decomposed" << endl;
    }
    return 0;
}

         问题3:在64为正整数范围内,子序列数目最多的数是哪一个?这个问题要用程序蛮力搜索,恐怕要运行很长时间,能否用数学知识推导出来?

         后续在讨论,没有想到好的方法解决。

3. 


By Andy @  2013年10月8日

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值