zoukankan      html  css  js  c++  java
  • 枚举--百练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;
    }
    

      

    柳暗花明又一村
  • 相关阅读:
    phpcurl使用
    系统常见问题
    java虚拟机CPU占用率过高排查方法
    oracle常用维护SQL
    PPT常用演示技能
    VS快捷键
    微软企业库缓存使用
    Oracle导sql的一个简便方法
    领域驱动设计
    sqluldr2
  • 原文地址:https://www.cnblogs.com/ucandoit/p/8469218.html
Copyright © 2011-2022 走看看