原题链接:跳跳 - 题目 - Daimayuan Online Judge
解题思路:因为本题的魔法必须是由两个整数构成,所以可以用一对魔法移动的,也就是说他们的x和y的改变量的绝对值,在除以他们的最大公因数后必定相等(比如3,2和6,4可以互通,他们都除以自己的最大公因数后得到的都是3,2)。
也就是说,只要记录一个方向的魔法,并且保证每个魔法的x和y都互质,即步长最小,那么之后能通过的点,必定是这个魔法执行整数次的结果。那么对于每两个点之间差的绝对值,除以他们的最大公因数后,就可以去查找原本的魔法中是否有一样的数值。原本的魔法可以支持这两个点的相互移动,则必然有相同的一对数字。而如果没有,则入队。
最终输出答案时要乘2,因为我们只记录了单向移动的魔法。
AC代码:
#include<bits/stdc++.h>
using namespace std;
long long x[510],y[510],n;
vector<long long> mx;
vector<long long> my;
int main(){
cin>>n;
for(int i=0;i<n;i++){//输入
scanf("%lld %lld",&x[i],&y[i]);
}
for(int i=0;i<n-1;i++){//查找,两重循环保证每个点两两之间都配对一次
for(int j=i+1;j<n;j++){//从i+1开始防止记录自己到自己
long long dx,dy,bk=1;
bool flag=1;//记录这两个点之间的移动是否需要新的魔法
dx=abs(x[i]-x[j]);//记录差的绝对值
dy=abs(y[i]-y[j]);
if(dx!=0&&dy!=0){//如果都不是0,则求他们的最大公因数,然后除以他们本身,得到能连接两点且步长最小的魔法
bk=__gcd(dx,dy);
dx/=bk;
dy/=bk;
}
else{//如果有为0的,则不为0的那一个步长最小必定为1
if(dx!=0) dx=1;
if(dy!=0) dy=1;
}
for(int k=0;k<mx.size();k++){//循环查找是否以前有过该魔法
if(dx==mx[k]&&dy==my[k]){//如果有则直接标记并退出
flag=0;
break;
}
}
if(flag){//如果不是提前退出则flag默认1,添加该魔法
mx.push_back(dx);
my.push_back(dy);
}
}
}
cout<<mx.size()*2;//因为是往返所以要乘以二
return 0;
}