您的位置:首页 > 其它

波老师(teacher/1S/64M)

2016-08-07 11:11 309 查看
【题目描述】

波波老师是一个地理老师。有一天他上课的时候,他在地图上标记了N个点,第i个点在点(Xi,Yi)。他想知道,是否存在四个点(A,B,C,D)(A<B,C<D,A≠C或者B≠D),使AB之间的曼哈顿距离和CD之间的曼哈顿距离相等。

如果存在这样的四个点,输出YES,否则输出NO。

 

【输入格式】

输入文件第一行是一个T(T≤50),表示有T组数据。

接下来有T组数据,每组数据第一行是两个整数N,M,表示点的个数以及点的坐标的边界,然后有N行,第i行有两个整数Xi,Yi表示第i个点的坐标(Xi,Yi)(0
10226
≤Xi,Yi≤M)

 

【输出格式】

输出文件有T行,每一行为YES或者NO。

 

【输入】

2

3 10

1 1

2 2

3 3

4 10

8 8

2 3

3 3

4 4

 

【输出】

YES

NO

80%的数据,n<=1000,m<=100000
100的数据,n<=100000,m<=100000
===========================================================首先我们要知道,所谓的曼哈顿距离,其实就是dis(I,j)=|xi-xj|+|yi-yj|。Lpq神犇因为不知道曼哈顿距离而计算了直线距离,无奈爆零了。这题虽然数据规模n<=10^5,但却可以用暴力ac。究竟是为什么呢?仔细读题,我们可以从m的范围入手。因为m的范围最多只有10^5,那么曼哈顿距离最多只有2*10^5,可以用计数排序统计是否出现过。这样,我们就可以只枚举两个点,计算它们的曼哈顿距离并标记起来。如果发现当前两个点的曼哈顿距离已经被标记过,那么就可以直接输出yes并退出。但是显然有个问题,n<=10^5,枚举两个点可能会达到10^10的复杂度(不过实际上并没有达到这个复杂度)。假如没有任意两个点的曼哈顿距离相同,不是会TLE吗?然而,根据鸽巢原理可知,这n*(n-1)/2对点会产生n*(n-1)/2种曼哈顿距离,而且因为它大于2*10^5,所以一定会产生重复!在最坏情况下,前2*10^5种距离都互不相同,下一对点的距离就必定属于前面这些出现过的距离中的一种。因此,本算法的复杂度应该是min(n^2,2*10^5),不超时。这也正应了我们oiers最喜欢的那句话:暴力出奇迹。不过在考试的时候我并没有想这么多,只考虑能拿到80%的分,因此数组也只开了10^3,导致剩下两组数据RE了。数组开小了是非常白痴的错误,也十分的令人痛心。以后一定要杜绝这种错误。

另外,事实上,当n充分大时,必然会有满足题意条件的点对存在,这时可以不必枚举,直接输出yes。(但我不会证明)
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>

using namespace std;

const int maxn = 1e5 + 9;
const int maxm = 1e5 + 9;

struct Tnode {
int X, Y;
Tnode() {
X = Y = 0;
}
} points[maxn];

int t;
bool f[maxm << 1]; //f[i]表示是否出现过一对点的曼哈顿距离为i

int main() {
ios::sync_with_stdio(false);
freopen("teacher.in", "r", stdin);
freopen("teacher.out" , "w", stdout);
cin >> t;

while(t--) {
memset(f, false , sizeof f);

int n, m;
cin >> n >> m;

for(int i = 0; i < n; i++)
cin >> points[i].X >> points[i].Y;

bool isok = false; //是否找到了四个点满足题意要求

for(int i = 0; i + 1 < n && !isok; i++) //枚举两个点
for(int j = i + 1; j < n && !isok; j++) {
int dis = abs(points[i].X - points[j].X) + abs(points[i].Y - points[j].Y);
//计算它们的曼哈顿距离

if(f[dis]) { //如果曾经出现过相同的
cout << "YES" << endl;
isok = true; //停止寻找
}

f[dis] = true; //标记这个距离出现过
}

if(!isok) cout << "NO" << endl; //找遍了也没有相同的
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: