百练-2812:恼人的青蛙(暴力枚举+剪枝优化)

总时间限制: 2000ms
单个测试点时间限制: 500ms
内存限制:65536kB

描述

在韩国,有一种小的青蛙。每到晚上,这种青蛙会跳越稻田,从而踩踏稻子。农民在早上看到被踩踏的稻子,希望找到造成最大损害的那只青蛙经过的路径。每只青蛙总是沿着一条直线跳越稻田,而且每次跳跃的距离都相同。
在这里插入图片描述
如下图所示,稻田里的稻子组成一个栅格,每棵稻子位于一个格点上。而青蛙总是从稻田的一侧跳进稻田,然后沿着某条直线穿越稻田,从另一侧跳出去
在这里插入图片描述
如下图所示,可能会有多只青蛙从稻田穿越。青蛙的每一跳都恰好踩在一棵水稻上,将这棵水稻拍倒。有些水稻可能被多只青蛙踩踏。当然,农民所见到的是图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
思路:

1.坐标排序
2.将点两两组合,构成起始的两个点,得出跳跃距离
3.剪枝(关键):两步过后(因为必须踩3棵及以上水稻),超出稻田范围的,剪掉;前一步在稻田内的剪掉(因为跳跃距离太短,青蛙跳不过来)
4.一步一步往下走,若落脚点没有被标记(即此水稻没有被踩过,跳出,进行下次枚举)
5.重复以上过程,直到枚举结束,答案取每次结果的最大值

代码:

#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
int n,m,t,mx,my,cx,cy,dx,dy,ans,maxx,flag;
bool vis[5010][5010];
struct ak
{
	int x;
	int y;
}a[5010];
bool cmp(ak xx,ak yy)
{
	if(xx.x==yy.x) return xx.y<yy.y;
	else return  xx.x<yy.x;
}
bool check(int x,int y)//检测是否在稻田内
{
	if(x>=1&&x<=n&&y>=1&&y<=m) return 1;
	else return 0;
}
int main( )
{
	ios::sync_with_stdio(false);
	cin>>n>>m>>t;
	for(int i=1;i<=t;i++)
	{
		cin>>a[i].x>>a[i].y;
		vis[a[i].x][a[i].y]=1;//标记此点被踩过
	}
	sort(a+1,a+t+1,cmp);//坐标排序,先按 x ,再按 y
	for(int i=1;i<t;i++)
	{
		mx=a[i].x,my=a[i].y;
		for(int j=i+1;j<=t;j++)
		{
			cx=a[j].x,cy=a[j].y;//枚举起始两点
			dx=cx-mx,dy=cy-my;
			if(mx+2*dx<1||mx+2*dx>n) break;
			//如果最起始点的 x 坐标加上两步后,超出稻田范围
			//直接结束此次枚举,枚举下一个最起始点
			//因为,排序按照 x 排序,它不行,他后面的也不行
			if(my+2*dy<1||my+2*dy>m) continue;
			//如果 y 超出范围,枚举下一个次起始点
			if(check(mx-dx,my-dy)) continue;
			//判断前一步是否在稻田内
			ans=1,flag=0;
			while(check(cx,cy))
			{
				if(vis[cx][cy]==0) 
				{
					flag=1;
					//如果落脚点没被踩过,标记,跳出
					break;
				} 
				cx+=dx,cy+=dy;
				ans++;
			}
			if(flag==0) maxx=max(maxx,ans);
			//最终结果取最大值
		}
	}
	cout<<maxx; 
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值