描述
在韩国,有一种小的青蛙。每到晚上,这种青蛙会跳越稻田,从而踩踏稻子。农民在早上看到被踩踏的稻子,希望找到造成最大损害的那只青蛙经过的路径。每只青蛙总是沿着一条直线跳越稻田,而且每次跳跃的距离都相同。
如下图所示,稻田里的稻子组成一个栅格,每棵稻子位于一个格点上。而青蛙总是从稻田的一侧跳进稻田,然后沿着某条直线穿越稻田,从另一侧跳出去
如下图所示,可能会有多只青蛙从稻田穿越。青蛙的每一跳都恰好踩在一棵水稻上,将这棵水稻拍倒。有些水稻可能被多只青蛙踩踏。当然,农民所见到的是图4中的情形,并看不到图3中的直线,也见不到别人家田里被踩踏的水稻,。
根据图4,农民能够构造出青蛙穿越稻田时的行走路径,并且只关心那些在穿越稻田时至少踩踏了3棵水稻的青蛙。因此,每条青蛙行走路径上至少包括3棵被踩踏的水稻。而在一条青蛙行走路径的直线上,也可能会有些被踩踏的水稻不属于该行走路径
①不是一条行走路径:只有两棵被踩踏的水稻;
②是一条行走路径,但不包括(2,6)上的水道;(这句话什么意思?求大佬指点!)
③不是一条行走路径:虽然有3棵被踩踏的水稻,但这三棵水稻之间的距离间隔不相等。
请你写一个程序,确定:在一条青蛙行走路径中,最多有多少颗水稻被踩踏。例如,图4的答案是7,因为第6行上全部水稻恰好构成一条青蛙行走路径。
输入
从标准输入设备上读入数据。第一行上两个整数R、C,分别表示稻田中水稻的行数和列数,1≤R、C≤5000。第二行是一个整数N,表示被踩踏的水稻数量, 3≤N≤5000。在剩下的N行中,每行有两个整数,分别是一颗被踩踏水稻的行号(1R)和列号(1C),两个整数用一个空格隔开。而且,每棵被踩踏水稻只被列出一次。
输出
从标准输出设备上输出一个整数。如果在稻田中存在青蛙行走路径,则输出包含最多水稻的青蛙行走路径中的水稻数量,否则输出0。
样例输入
6 7
14
2 1
6 6
4 2
2 5
2 6
2 7
3 4
6 1
6 2
2 3
6 3
6 4
6 5
6 7
样例输出
7
#include<iostream>
#include<cstring>
#include<cstdlib>
using namespace std;
struct Dz{
int x,y;
};
Dz dz[5010];
int r,c,n;
int cmp(const void *a,const void *b){
Dz dz1 = *(Dz *)a;
Dz dz2 = *(Dz *)b;
if(dz1.x == dz2.x)
return dz1.y - dz2.y;
else
return dz1.x - dz2.x;
}
int getstep(int i,int dx,int dy){
int px,py;
int step = 1;
Dz tdz;
px = dz[i].x;
py = dz[i].y;
while(1){
px += dx;
py += dy;
if(px >= 1 && px <= r && py >= 1 && py <= c){
tdz.x = px;
tdz.y = py;
if(bsearch(&tdz,dz,n,sizeof(Dz),cmp))
++step;
else{
step = 0;
break;
}
}
else
break;
}
return step;
}
int main(){
int i,j;
int dx,dy,px,py,max;
max = 0;
scanf("%d%d%d",&r,&c,&n);
for(i = 0;i < n; ++i){
scanf("%d%d",&dz[i].x,&dz[i].y);
}
qsort(dz,n,sizeof(Dz),cmp);
for(i = 0;i < n - 1; ++i){
for(j = i + 1;j < n; ++j){
dx = dz[j].x - dz[i].x;
dy = dz[j].y - dz[i].y;
px = dz[i].x - dx;//前一个点的横坐标。
py = dz[i].y - dy;
if(px >= 1 && px <= r && py >= 1 && py <= c)
continue;//该点在已被访问过的路径上
if(dz[i].x + max * dx > r)
break;//该路径即使存在也不是最大,因为排序主元是x,所以无需尝试剩余的y。
py = dz[i].y + max * dy;
if(py > c || py < 1)
continue;//该路径即使存在也不是最大。
int steps = getstep(i,dx,dy);
if(steps > max)
max = steps;
}
}
if(max <= 2)
max = 0;
printf("%d",max);
return 0;
}
完全不会。
最原始的想法:
两两遍历所有被踩的稻子(坐标),两个稻子即可得到一条路径,求出路径长度。(应该会tle)
优化:
将所有稻子(坐标)快排:
1.便于使用二分搜索;
2.可以剪枝(从路径的头部开始比较)防止重复计算和无意义的计算。
#include<iostream>
#include<algorithm>
using namespace std;
const int MAX = 5010;
int r,c,n;
struct Gua{
int x,y;
bool operator < (const Gua& rhs) const{
if(this -> x == rhs.x)
return this -> y < rhs.y;
else
return this -> x < rhs.x;
}
};
Gua gua[MAX];
int main(){
int i,j;
scanf("%d%d%d",&r,&c,&n);
for(i = 0;i < n; ++i){
scanf("%d%d",&gua[i].x,&gua[i].y);
}
sort(gua,gua + n);
int res = 0;
for(i = 0;i < n - 1; ++i){
for(j = i + 1;j < n; ++j){
int x1 = gua[i].x;
int y1 = gua[i].y;
int x2 = gua[j].x;
int y2 = gua[j].y;
int dx = x2 - x1;
int dy = y2 - y1;
if(x1 - dx > 0 && x1 - dx <= r && y1 - dy > 0 && y1 - dy <= c){
continue;
}
if(x1 + res * dx > r)
break;
int ny = y1 + res * dy;
if(ny < 1 || ny > c)
continue;
int ans = 1;
Gua np;
np.x = x2;
np.y = y2;
while(np.x > 0 && np.x <= r && np.y > 0 && np.y <= c){
if(binary_search(gua,gua + n,np))
++ans;
else{
ans = 0;//若路径一半就中断那就不是路径啊。
break;
}
np.x += dx;
np.y += dy;
}
if(ans >= 3 && ans > res)
res = ans;
}
}
printf("%d",res);
return 0;
}
二刷还是不会k(;´д`)ゞ
MLE :开数组记录有没有稻子,5000*5000的数组???
TLE:没有优化剪枝,先试一试最大长度是否超出范围。
WA:有路径必须是完整路径,见注释。
讨厌的青蛙!!!讨厌!!!