连线游戏
题目描述
Farmer John最近发明了一个游戏,来考验自命不凡的贝茜。游戏开始的时候,FJ会给贝茜一块画着 N (2 <= N <= 200)个不重合的点的木板,其中第 i 个点的横、纵坐标分别为 X_i 和 Y_i (-1,000 <= X_i <=1,000; -1,000 <= Y_i <= 1,000)。
贝茜可以选两个点画一条过它们的直线,当且仅当平面上不存在与画出直线平行的直线。游戏结束时贝茜的得分,就是她画出的直线的总条数。为了在游戏中胜出,贝茜找到了你,希望你帮她计算一下最大可能得分。
输入格式
第 1 行: 输入 1 个正整数:N
第 2..N+1 行: 第 i+1 行用 2 个用空格隔开的整数 X_i、Y_i,描述了点 i 的坐标。
输出格式
输出 1 个整数,表示贝茜的最大得分,即她能画出的互不平行的直线数 。
样例数据 1
输入
4
-1 1
-2 0
0 0
1 1
输出
4
备注
【输出说明】
贝茜能画出以下 4 种斜率的直线:-1,0,1/3 以及 1。
算法分析:
方法一: 暴力枚举+暴力扫描去重 期望得分:90(数据弱:100) 时间复杂度:n4(一卡常就死)
1)读入数据后,两两枚举得到全部斜率;
2)每枚举一个,搜索前面已存储的每一个,若有重复,则不加入,若没有,加入,个数加1;
3)输出个数;
注意:
1、由于可能会出现x[i]-x[j]=0的特殊情况,若作为除数会直接导致报错,所以要专门进行单列讨论。
2、double精度的两个数不能直接进行相等的比较一般为两数相减的绝对值小于一个极小值为相等判定,且注意精度一定要高,但是若太高可能会多解,不够高可能会少解。
Source:
#include
#include
#include
#include
#include
#include
using namespace std;
int n,xx,yy;
/*n:个数; xx:横坐标读入; yy:纵坐标读入*/
double x[210],y[210];
/*x:横坐标存储; y:纵坐标存储*/
double sc[40010],c;
/*sc:斜率存储; c:斜率临时存储判断*/
bool able;
/*able:判断是否已存储*/
inline void R(int &v)/*读入优化*/
{
v=0;
char c=0;
bool p=true;
while(c>'9'||c<'0')
{
if(c=='-')
{
p=false;
}
c=cin.get();
}
while(c<='9'&&c>='0')
{
v=(v<<3)+(v<<1)+c-'0';
c=cin.get();
}
if(p==false)
{
v=-v;
}
}
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(NULL); /*cin解绑*/
//freopen("lines.in","r",stdin);
//freopen("lines.out","w",stdout);
R(n);
for(int i=1;i<=n;++i) /*读入&存储*/
{
R(xx);
x[i]=xx;
R(yy);
y[i]=yy;
}
int top=0; /*个数统计*/
for(int i=1;i<=n;++i)
{
for(int j=i+1;j<=n;++j) /*枚举每一条直线*/
{
if(x[i]-x[j]!=0)
{
c=(y[i]-y[j])/(x[i]-x[j]); /*计算斜率*/
}
else
{
c=10000000; /*单独讨论除数为0的情况*/
}
int o=top;
for(int k=1;k<=o;++k)
{
if(abs(sc[k]-c)<0.00000000001)/*double判断是否相等*/
{
able=true; /*若相等,更改标记*/
break; /*跳出循环*/
}
}
if(able==true)
{
able=false;
}
else
{
top++; /*若未被存储*/
sc[top]=c; /*加入存储区*/
}
}
}
cout<
方法二: 暴力枚举+stl(set)去重(代码异常简单,可以说本题为专设给set的裸题······)
1)读入数据后,两两枚举得到全部斜率;
2)每枚举一个,放入set;
3)输出set中的元素个数;
Source:
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int n,xx,yy;
/*n:个数; xx:横坐标读入; yy:纵坐标读入*/
double x[210],y[210];
/*x:横坐标存储; y:纵坐标存储*/
double c;
/*c:斜率临时存储判断*/
bool able;
/*able:判断是否已存储*/
set s;
/*stl:set:可直接对加入的数据去重*/
inline void R(int &v) /*读入优化*/
{
v=0;
char c=0;
bool p=true;
while(c>'9'||c<'0')
{
if(c=='-')
{
p=false;
}
c=cin.get();
}
while(c<='9'&&c>='0')
{
v=(v<<3)+(v<<1)+c-'0';
c=cin.get();
}
if(p==false)
{
v=-v;
}
}
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(NULL); /*cin解绑*/
//freopen("lines.in","r",stdin);
//freopen("lines.out","w",stdout);
R(n);
for(int i=1;i<=n;++i) /*读入&存储*/
{
R(xx);
x[i]=xx;
R(yy);
y[i]=yy;
}
for(int i=1;i<=n;++i) /*枚举每一条直线*/
{
for(int j=i+1;j<=n;++j)
{
if(x[i]-x[j]!=0)
{
c=(y[i]-y[j])/(x[i]-x[j]); /*计算斜率*/
}
else
{
c=10000000; /*单独讨论除数为0的情况*/
}
s.insert(c); /*插入set*/
}
}
cout<
方法三: 暴力枚举+快速排序+去重
1)读入数据后,两两枚举得到全部斜率;
2)每枚举一个,放入存储空间;
3)快速排序使相同斜率相邻;
4)手动去重;
Source:
无,只需在第一种后面加上sort排序即可;

Summary:
本题其实并不算难,但是却需要考虑一些琐碎问题,所以编写过程中一定要考虑全面,并且对于我们已有的stl也要有所了解,必要时可以使用来简化编写和运算。以上三种方法中,明显就是用set的算法最为简单。