给你n个点的坐标(x,y)。求哈密顿距离和欧几里德距离相同的点对有多少,所给的点可能是重合的。
哈密顿距离:|xi-xj|+|yi-yj|,欧几里德距离:根号下((xi-xj)^2+(yi-yj)^2)。把两边平方一下,再一消去,就可发现,只有当(xi-xj)和(yi-yj)至少有一个为0时,两种距离才相等,就是两个点的横纵坐标至少有一个是一样的。
所以,因为有重点,就显得有点麻烦,但其实想了想,也不麻烦啊。首先把所有点按x坐标排序,每类所有x坐标相同的点,加入有m个,取C(m,2)。不管纵坐标相不相同,都可以这么取。然后再按y坐标排序,同样对每类所有y坐标相同的点,取个C(m,2)。这时就会发现,那些两两相同的,被计算了两次。所以找到每类x和y都相同的点,也取C(m,2)。把最后这个减去就好了。
代码:
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define maxn 200002
struct node
{
int x, y;
}a[maxn];
bool cmp1(node a, node b)
{
if (a.x < b.x)
return 1;
else if (a.x == b.x&&a.y < b.y)
return 1;
else
return 0;
}
bool cmp2(node a, node b)
{
if (a.y < b.y)
return 1;
else if (a.y == b.y&&a.x < b.x)
return 1;
else
return 0;
}
int main()
{
//freopen("input.txt", "r", stdin);
int n;
long long cnt = 0, ans = 0, l = 0;
scanf("%d", &n);
for (int i = 0; i < n; ++i)
scanf("%d%d", &a[i].x, &a[i].y);
sort(a, a + n, cmp1);
cnt = 1;
for (int i = 1; i < n; ++i)
{
if (a[i].x == a[i - 1].x)
cnt++;
else
{
ans += cnt*(cnt - 1) / 2;
cnt = 1;
}
}
ans += cnt*(cnt - 1) / 2;
cnt = 1;
sort(a, a + n, cmp2);
for (int i = 1; i < n; ++i)
{
if (a[i].y == a[i - 1].y)
cnt++;
else
{
ans += cnt*(cnt - 1) / 2;
cnt = 1;
}
}
ans += cnt*(cnt - 1) / 2;
cnt = 1;
for (int i = 1; i < n; ++i)
{
if (a[i].y == a[i - 1].y&&a[i].x == a[i - 1].x)
cnt++;
else
{
ans -= cnt*(cnt - 1) / 2;
cnt = 1;
}
}
ans -= cnt*(cnt - 1) / 2;
cnt = 1;
printf("%I64d\n", ans);
//while (1);
//system("pause");
return 0;
}