HDU5621——数学应用(多边形内对角线交点个数) + 数论 + unsigned long long的应用

题目描述:

KK's Point

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 713    Accepted Submission(s): 238


Problem Description
Our lovely KK has a difficult mathematical problem:He points  N(2N105) points on a circle,there are all different.Now he's going to connect the  N points with each other(There are no three lines in the circle to hand over a point.).KK wants to know how many points are there in the picture(Including the dots of boundary).
 

Input
The first line of the input file contains an integer  T(1T10), which indicates the number of test cases.

For each test case, there are one lines,includes a integer  N(2N105),indicating the number of dots of the polygon.
 

Output
For each test case, there are one lines,includes a integer,indicating the number of the dots.
 

Sample Input
 
   
2 3 4
 

Sample Output
 
   
3 5
题意:

一个圆周上点下了互不重合的N(2≤N≤105)个点,将这N个点两两相连(圆内没有三条线交于一个点的情况),图形中一共有多少个交点(包括边界上的点)。

解析:

同样,这也是一道找规律的题目,将这N个点两两相连,当N>3时,在外部则形成了一个多边形,然后内部的连线则是多边形的对角线,而这道题便转换为多边形内对角线交点个数的问题,即原问题转换成数学问题:

给定一个凸N边形,满足性质:任何三条对角线都不交于同一点.在这样一个多边形的内部,它的所有对角线共形成多少个交点?

由于每一个交点对应着两条相交的对角线,而两条相交的对角线确定一个四边形,所以计算交点的个数即是计算多边形内四边形的个数,所以原问题又转换为多边形内四边形的个数,而四边形四个点,所以这就是我们熟悉的组合问题了(在N个点中任意找四个点形成一个四边形),那么交点个数=四边形个数=C(N,N-4).考虑特殊情况后,很快便得出完整代码:

#include
#include
using namespace std;
typedef long long ll;
int main()
{
    int T;
    ll N;
    while(scanf("%d",&T)==1&&T)
    {
        while(T--)
        {
            scanf("%I64d",&N);
            if(N==2)  printf("2\n");
            else if(N==3)  printf("3\n");
            else if(N>3)
            {
                ll sum = (N * (N - 1) * (N - 2) *(N - 3)) / 24;
                printf("%I64d\n",sum+N);
            }

        }
    }
    return 0;
}
提交答案后,却得出这样的回复:


于是,我便开始纳闷,为什么会这样呢?规律都正确了,为什么会得出Wrong Answer呢?

然后我注意到了N的取值范围,N<=10^5,所以我考虑是不是long long的数据范围不够大?于是我很快便得出以下代码:

#include
#include
using namespace std;
typedef unsigned long long ull;
int main()
{
    int T;
    ull N;
    while(scanf("%d",&T)==1&&T)
    {
        while(T--)
        {
            scanf("%llu",&N);
            if(N==2)  printf("2\n");
            else if(N==3)  printf("3\n");
            else if(N>3)
            {
                ull sum = (N * (N - 1) * (N - 2) *(N - 3)) / 24;
                printf("%llu\n",sum+N);
            }

        }
    }
    return 0;
}
可依旧还是:


于是我想不明白了,数据改为unsigned long long类型了,已经是整型范围内最大的数据类型了,难道还是超过最大范围吗?于是我重新看了一下N的取值范围,然后发现四个连乘之后,数据达到了10^20级别,而下面是各种数据类型的数据范围:

HDU5621——数学应用(多边形内对角线交点个数) + 数论 + unsigned long long的应用_第1张图片

然后发现unsigned long long的最大值也只是10^19次方级别的数据而四个连乘之后数据范围明显超过了unsigned long long的最大值,那么我们要怎么做才能得到正确答案呢?我们发现,连续的两个数必定有一个是偶数,连续的三个数必定有一个是3的倍数,同理,连续的四个数必定有一个是4的倍数,所以呢,我们可以不必要直接把四个含有N的表达式全部相乘,可以连续两个乘过之后,除以2,然后再乘一个,除以3,这样的话,在N取得最大值10^5的情况下,前面四个连乘后得出的结果为:16665666684999900000,数据范围在unsign long long之内,这样的话,我们解决了问题。再除以4,这样的话,所以得出以下完整代码:

#include
#include
using namespace std;
typedef unsigned long long int ull;
int main()
{
    int T;
    ull N;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%I64u",&N);
        ull sum = N;
        if(N>3)
            sum += N * (N - 1) / 2 * (N - 2) / 3 * (N - 3) / 4;   //ULL只有19位
        printf("%I64u\n",sum);
    }
    return 0;
}

总结:这道题其实不难,考的是数学应用,但是这道题考察了平时会比较忽略的知识(unsigned long long,溢出最大数据范围等问题),所以呢,我们才一时找不出错误,这更警醒我们要注重基础,多了解一点总是没有害处的。然后平时要多积累,注意数学问题之间的转换,可以化难为易,并且转换成我们能够解决的问题。



你可能感兴趣的:(解题报告,ACM一些常用的数学问题)