青蛙会每天晚上跳过稻田,从而踩倒稻子,同一只青蛙每一步跳的步长相等,但不同青蛙跳跃的步长可以不等,青蛙可以自己选择跳跃的方向,但是只能沿着一条直线跳跃。农民每天早上起床看到被踩踏的稻子,希望能找到造成最大伤害的青蛙的路径。稻田里的稻子形成了一个栅格,没根稻子都处于栅格的一个格点上。而青蛙总是会从稻田的一侧跳入,并沿着直线从另一侧跳出,其中每条青蛙行动路径中至少要有三颗水稻。
农民只能看到被踩倒的稻子(右图),并不能看到青蛙的路径(左图)
程序输入:
1.第一行输入两个整数R,C,分别代表稻田中水稻的行数或列数,1<=R,C<=5000
2.第二行输入整数N,表示被踩倒的稻子数目。
3.从第三行开始的N行,每行输入两个整数,分别表示被踩踏的稻子在稻田中的行数以及列数,用逗号隔开
程序输出:
输出一个整数,如果存在青蛙行走路径,这个整数表示包含最多水稻的的青蛙行走路径中的水稻数量;如果不存在,则输出0
思路:
如果枚举每个被踩踏的稻子作为路径起点,枚举每个可能的路径方向,对每个路径枚举步长,则枚举的数量过于庞大,因此为了减少枚举的数量,我们还是考虑提前排除不可能的情况。
假设一只青蛙跳入稻田中踩到的第一和第二棵水稻分别是(x1,y1),(x2,y2),则这只青蛙在x方向以及y方向上的步长分别为:
dx = x2-x1;
dy = y2-y1;
那么:
1.如果(x1-dx,y1-dy)不在稻田之外,则说明(x1,y1)不能作为第一棵水稻
2.将这条路径的最后一个点记作(xk,yk),则如果(xk+dx,yk+dy)没有在稻田之外,则表示这条路径也不符合要求。
3.MaxStep作为当前找到的最长步长,如果青蛙从(x1,y1)出发最多经过MaxStep步已经跳出稻田外,则该条路径也不是我们要找的路径
代码:
#include <stdlib.h>
#include <stdio.h>
#include <algorithm>
using namespace std;
int r, c, n;
struct PLANT {
int x, y;
};
PLANT plants[5001];
PLANT plant;
int SearchPath(PLANT secPlant, int dX, int dY);
int main()
{
int i, j, dX, dY, pX, pY, steps, max = 2;
//获取稻田的行与列和稻田中被踩倒的稻子数,然后依次获取被踩倒的稻子的行列数
//这里x方向是上下,y方向是左右
scanf("%d %d", &r, &c);
scanf("%d", &n);
for (i = 0; i < n; i++)
{
scanf("%d,%d", &plants[i].x, &plants[i].y);
}
sort(plants, plants + n);
//开始枚举前两个点
for (i = 0; i < n - 2; i++) //plants[i]是第一个点
{
for (j = i + 1; j < n - 1; j++) //plants[j]是第二个点
{
//获取这个路径上的x方向以及y方向上的步长
dX = plants[j].x - plants[i].x;
dY = plants[j].y - plants[i].y;
//根据步长预测在第一步之前的那一步位置
pX = plants[i].x - dX;
pY = plants[i].y - dY;
if (pX <= r && pX >= 1 && pY <= c && pY >= 1)
{
//如果现在枚举的前两个点的路径的前一个点在稻田中,则说明现在选的第二个点
//导致当前步长太短,所以不合理,选择下一个点作为第二个点
continue;
}
if (plants[i].x + (max - 1)*dX > r )
//如果当前枚举的这条路径在当前获得的最多步数的情况下,x方向已经超出了稻田的范围
//则说明早就越界了。即x方向步长太长,由于被踩倒的稻子已经按照先按x后按y排好了序
//这时如果选择其他点作为第二个点,则只会步长更长,因此要取下一个点作为第一个点
break;
pY = plants[i].y + (max - 1)*dY;
if (pY > c || pY < 1) //如果y方向早就越界,那么应该换第二个点再试
continue;
steps = SearchPath(plants[j], dX, dY);
if (steps > max)
max = steps;
}
}
if (max == 2)
max = 0;
printf("%d\n", max);
}
bool operator<(const PLANT &p1, const PLANT &p2)
{
//先按照x方向排序,如果x相同则按照y方向排序
if (p1.x == p2.x)
return p1.y < p2.y;
return p1.x < p2.x;
}
//判断从secPlant点开始,步长为dx,dy,那么最多能走几步
int SearchPath(PLANT secPlant, int dX, int dY)
{
int steps = 2;
PLANT plant;
plant.x = secPlant.x + dX;
plant.y = secPlant.y + dY;
while (plant.x <= r && plant.x >= 1 && plant.y <= c && plant.y >= 1)
{
if (!binary_search(plants, plants + n, plant)) //如果按照这条路径的一步并没有踩倒水稻,即这并非一条行走路径
{
steps = 0;
break;
}
plant.x += dX;
plant.y += dY;
steps++;
}
return steps;
}