跳跳 - 题目 - Daimayuan Online Judge
一种魔法:(A,B)==>(X,Y)->(X+A,Y+B),一次传送可以使用多次该魔法
问至少掌握多少种魔法
最少==>从一个点到另一个点要一来一回,想要最少的话肯定连直线过去再回来,这样是两种魔法如果走其它路径的话,比如先先横着再竖着,一来一回就4种魔法
所以求有几条直线,再乘2
这类似于蓝桥杯的直线问题,具体见第十二届蓝桥杯c++b组_m0_74087709的博客-CSDN博客
第十一届蓝桥杯c++b组_m0_74087709的博客-CSDN博客
但是我依照上面蓝桥杯类似题目的解法,将每条直线的斜率和截距放在set容器中,set有去重的功能,但是浮点数有精度误差,应该是这个原因导致的错误
错误代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<set>
using namespace std;
typedef pair<int,int>PII;
const int N = 510;
struct Node {
double x, y;
}l[N];
int main()
{
set<PII>s;
int n;
cin >> n;
for (int i = 1; i <= n; i++) cin >> l[i].x >> l[i].y;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (i == j) continue;
PII t;
t.first = (double)(l[j].y - l[i].y) / (l[j].x - l[i].x);
t.second =(double)(l[j].x * l[i].y - l[i].x * l[j].y) / (l[j].x - l[i].x);
s.insert(t);
}
}
cout << s.size()*2 << endl;
return 0;
}
其实完全可以避免浮点数的精度误差的,不需要求出直线的斜率,只要求出两点的横坐标之差和纵坐标之差,然后化为最简(同时除以它们的最大公约数),然后将其放入set容器里
注意n属于[10,500],n小于等于500,O(n^2)完全可以,我一开始看成是10500了好傻
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<set>
#include<cmath>
using namespace std;
typedef pair<int,int>PII;
const int N = 510;
struct Node {
int x, y;
}l[N];
int gcd(int a, int b) {
if (b == 0) return a;
return gcd(b, a % b);
}
int main()
{
set<PII>s;
int n;
cin >> n;
for (int i = 1; i <= n; i++) cin >> l[i].x >> l[i].y;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (i == j) continue;
int x = abs(l[i].x - l[j].x);
int y = abs(l[i].y - l[j].y);
PII t;
int tmp = gcd(x, y);
t.first = x / tmp;
t.second = y / tmp;
s.insert(t);
}
}
cout << s.size() * 2 << endl;
return 0;
}