枚举--百练2812--恼人的青蛙(内含枚举基本思想总结)

题目描述

跟关灯问题相似的地方是,第一眼都很懵逼,还是看了视频之后照着视频的思路过的;毕竟自己来的话效率奇低。

分析:

首先这是一道枚举问题。

枚举:就是从可能的解的集合中一一列举各个元素,判断其是否符合问题要求,符合的就是问题的解。

枚举问题的三个关键是:

一:给出解空间,建立简洁的数学模型。

二:减小解空间,即减小搜索的空间。

三:采用合适的搜索顺序

对于本题:

一:解空间是一条条线,每条线上有若干等距的点。数学模型:用dx,dy表示相邻点的x,y方向距离,则确定前两个点之后(确定了初始点与青蛙跳跃方向),再加上稻田的边界,就可知道这条线上有几个点。

二:首先最简单基本的枚举:枚举所有任意两点所成的线(其实数量级还是很大,第三步会进一步优化),求线上等距点。减小解空间的方法是:取点后,先判断一:其是不是“最开 始的两个点”(这一步具体实现要依赖于“三:采用合适的搜索顺序”),二:求出dx,dy,那么第二个点(x2,y2)加上(max-1)*dx,(max-1)*dy后,x和y是否已经越界(max是已经求出的中最长路径,初始为2,根据题目要求,如果最终结果max仍是二,max=0),如果已经越界,那么就直接考虑下一组点。

三: 对每一个点排序,x小的排在前面,x相等的话,y小的在前面。这样子的好处是:一,上文绿色高亮部分,在查找确定线上有几个点时,我们就可以进行二分查找,效率很高。另外,二:判断“两个点是不是线的起始点时”,我们只要按顺序取点即可,具体看代码(在代码高亮处,非常巧妙,仔细阅读):

#include <stdio.h>
#include <algorithm> 
using namespace std;

int r,c,n;

struct plant{
	int x,y;
};

plant plants[5001];
plant plantt;

bool operator < (const plant& a,const plant& b){
	if(a.x == b.x)
	return a.y<b.y;
	return a.x<b.x;
}

int searchpath(plant secplant,int dx,int dy){                          //确定前两个点之后,输入第二个点,求线上点数
	int s;
	plantt.x=secplant.x+dx;
	plantt.y=secplant.y+dy;
	s=2;
	while(plantt.x<=r && plantt.x>=1 && plantt.y>=1 && plantt.y<=c){
		if(!binary_search(plants,plants+n,plantt)){
			s=0;
			break;
		}
		plantt.x+=dx;
		plantt.y+=dy;
		s++;
	}
	return s;
}

int main() {
	freopen("in.txt","r",stdin);
	
	int dx,dy,px,py,max=2,steps; 
	
	scanf("%d %d",&r,&c);
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	scanf("%d %d",&plants[i].x,&plants[i].y);
	
	sort(plants,plants+n);
	
	for(int i=0;i<n-2;i++)                                           //按顺序枚举
		for(int l=i+1;l<n-1;l++){                                //为什么是 l<n-1 我没想明白   (不过n也行的其实)
			dx=plants[l].x-plants[i].x;
			dy=plants[l].y-plants[i].y;
			px=plants[i].x-dx;
			py=plants[i].y-dy;
			if(px>=1 && px<=r && py>=1 && py<=c)  continue;             //判断是不是“最开始的两个点”
			if(plants[i].x+(max-1)*dx>r) break;                         //这一行多一个等号(dx>=r)就能毁灭世界 
			if((plants[i].y+(max-1)*dy)>c || (plants[i].y+(max-1)*dy)<1) continue;         //与x方向是否越界的判断有很大不同,要注意 
			
			steps=searchpath(plants[l],dx,dy);
			if(steps>max) max=steps;
		} 
 	if(max==2) max=0;	printf("%d
",max);
    return 0;
}

  

柳暗花明又一村
原文地址:https://www.cnblogs.com/ucandoit/p/8469218.html