【算法笔记】枚举之讨厌的青蛙

青蛙会每天晚上跳过稻田,从而踩倒稻子,同一只青蛙每一步跳的步长相等,但不同青蛙跳跃的步长可以不等,青蛙可以自己选择跳跃的方向,但是只能沿着一条直线跳跃。农民每天早上起床看到被踩踏的稻子,希望能找到造成最大伤害的青蛙的路径。
稻田里的稻子形成了一个栅格,没根稻子都处于栅格的一个格点上。而青蛙总是会从稻田的一侧跳入,并沿着直线从另一侧跳出,其中每条青蛙行动路径中至少要有三颗水稻。

农民只能看到被踩倒的稻子(右图),并不能看到青蛙的路径(左图)

程序输入:

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;
}

猜你喜欢

转载自blog.csdn.net/yong_ss/article/details/79326865