前言
作者今天正式开始了自己准备明年机试的算法之路。使用的教材是洛谷的《深入浅出程序设计竞赛》。作为一个计科的学生,在绿群里瞻仰了很多大佬之后,才发现自己的代码能力有多弱。于是开始学习C++和算法。希望还不算太晚。
题目:洛谷P2181 对角线
对于一个n个顶点的凸多边形,它的任何三条对角线都不会交于一点。请求出图形中对角线交点的个数。
输入格式
输入只有一行一个整数n,代表边数。
输出格式
输出一个一行整数,代表答案。
说明和提示
- 对于50%的数据,保证 3≤n≤100
- 对于100%的数据,保证 3≤n≤10^5
思路
这个题需要用到非常巧妙地数学思维。首先分析凸多边形的对角线会怎样相交,对于凸多边形内的任意三条对角线来说,他们不会交于同一点。我们任意取一个交点来分析,发现这是由两条对角线,也就是四个不同的顶点构造而成的。这说明,任意四个顶点得到的两条对角线都能在凸多边形之内形成一个不重复的交点。那么现在问题就转化为,在n个顶点中选出四个不同的顶点。很明显,这是一个组合问题。那么我们可以直接得到,最后的答案就是C42。下面完成代码。(初次写算法,被各种条件限制薄纱了o(╥﹏╥)o)
代码
作者想出思路之后,很快写出来第一版本的代码,如下所示。
#include<cstdio>
#include<cmath>
int main()
{
int n;
scanf("%d",&n);
int amount = (n*(n-1)*(n-2)*(n-3))/24;
printf("%d",amount);
return 0;
}
遂立即丢进洛谷里进行检测,果不其然,直接砍下55分的好成绩(o(╥﹏╥)o)。这里就引出很重要的知识,在程序设计中,时间限制,内存限制,变量越界等问题也在编写代码的考量之中。不能为了得出正确答案而不考虑优化的问题。于是作者绞尽脑汁想出问题所在,我所使用的int太小了,洛谷检测的数据一定出现了很大的情况,int完全装不下,这个时候需要换成无符号的长长整型。第二次的代码如下所示。
#include<iostream>
using namespace std;
int main()
{
unsigned long long n;
cin >> n;
unsigned long long amount = (n*(n-1)*(n-2)*(n-3))/24;
cout << amount;
return 0;
}
作者换成unsigned long long之后,还是只拿下了82分。作者百思不得其解,思考很久也不知道哪里出现了问题。最后灵光乍现,问题出来了amount变量上。因为即使是ULL,连续乘四位也可能出现越界的问题,最好的解决方式是边乘边除,于是作者再次修改代码。
#include<iostream>
using namespace std;
int main()
{
unsigned long long n;
cin >> n;
unsigned long long amount = n*(n-1)/2*(n-2)/3*(n-3)/4;
cout << amount;
return 0;
}
这次终于拿下了100!!!!!
结尾
这是作者算法之路的第一道题目,非常具有纪念意义。作者感受到了coding的乐趣(但愿能够坚持下去),路还很长,加油吧!