您的位置:首页 > 其它

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

2016-02-17 20:18 501 查看
题目描述:


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(2≤N≤105) 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(1≤T≤10),
which indicates the number of test cases.

For each test case, there are one lines,includes a integer N(2≤N≤105),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<cstdio>
#include<algorithm>
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<cstdio>
#include<algorithm>
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级别,而下面是各种数据类型的数据范围:



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

#include<cstdio>
#include<algorithm>
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,溢出最大数据范围等问题),所以呢,我们才一时找不出错误,这更警醒我们要注重基础,多了解一点总是没有害处的。然后平时要多积累,注意数学问题之间的转换,可以化难为易,并且转换成我们能够解决的问题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: