• 枚举3--讨厌的青蛙


    枚举3--讨厌的青蛙 

    总结:

    根据前两点枚举

    提前排除其它不可能的情况

    一、题目

    题目
    问题描述:
    在一块被踩踏的田地里找寻被踩踏路径最长的一条道路,并输出被踩踏的稻田数目。
    其中:要求路线为直线(包括斜直线),至少有三颗稻子被踩到,每两颗被踩到的稻子之间的距离是相等的;
    输入为:第一行为总的行数r和列数c,第二行为共有多少颗水稻被踩,第三行往下为水稻被踩的行数和列数。
    输出为:最长的被踩踏的稻子数目,若没有则输出0。

    1.直线路径:每只青蛙总是沿着一条直线跳跃稻田
    2.相同间距:且每次跳跃的距离都相同
    3.有进有出:而青蛙总是从稻田的一侧跳进稻田, 然后沿着某条直线穿越稻田, 从另一侧跳出去
    4.多项干扰:可能会有多只青蛙从稻田穿越
    问题: 在各条青蛙行走路径中, 踩踏水稻最多的那一条上, 有多少颗水稻被踩踏

    如图有三条青蛙可以跳的路

    输入
    6 7 //6行7列
    14 //被踩的数量14棵
    2 1 //稻子的坐标
    3 4
    5 3... (总共14个)

    6 7
    14
    2 1
    2 3
    2 5
    2 6
    2 7
    3 4
    4 2
    6 1
    6 2
    6 3
    6 4
    6 5
    6 6
    6 7


    输出
    7 (单只青蛙踩最多的步数,没有输出为0)

    二、分析

    分析:
    解法一:
    枚举每一条路径的情况, 起点可能性*方向可能性*步长可能性=非常多(不可取)
    起始点:5000 方向:5000 步长:5000 总复杂度5000^3,不得行
    解法二:
    (1)、
    确定前两颗被踩踏的坐标,起始点,方向,步长就都确定了
    设坐标为(X1,Y1),(X2,Y2),则两者之间的为间隔dX=X2-X1,dY=Y2-Y1;
    (2)、
    要求第一点的前一点要在稻田外,若不在,则第一点不满足第一点
    第三点则要求在稻田内,最后一点的后面一点要落在稻田外
    设坐标(X0,Y0),(X3,Y3);X0=X1-dX,Y0=Y1-dY;Xi=X1+i*dX,Yi=Y1+i*dY;(i>=3)
    (3)、
    猜测的过程中一定要尽快的排除错误!当满足如下条件的时候,就要排除最先选取的两点了:
    a,青蛙不能经过一跳从稻田外跳到第一点上去;
    b,按照第一点和第二点确定步长,从第一点出发,青蛙最多经过(MAXSTEPS-1)步,就会跳跃到稻田之外;
    MAXSTEPS是当前已经找到的最好的答案。
    (4)、
    选取合适的数据结构:
    关于被踩踏的水稻坐标最好采用单个变量的形式,简单清晰,此处采用结构体表示坐标;
    struct Plant{
    int x,y;//x,y分别表示水稻的行号和列号
    }
    (5)、
    猜测一条行走路径,需要从当前位置(X,Y)出发时,判断(X+dX,Y+dY)位置的水稻是否被踩踏;
    先采用sort()函数对plants中的元素排序,再用binary_search()从中查找元素(X+dX,Y+dY)。

    三、代码

      1 /*
      2 枚举3--讨厌的青蛙 
      3 题目
      4 问题描述:
      5 在一块被踩踏的田地里找寻被踩踏路径最长的一条道路,并输出被踩踏的稻田数目。
      6 其中:要求路线为直线(包括斜直线),至少有三颗稻子被踩到,每两颗被踩到的稻子之间的距离是相等的;
      7 输入为:第一行为总的行数r和列数c,第二行为共有多少颗水稻被踩,第三行往下为水稻被踩的行数和列数。
      8 输出为:最长的被踩踏的稻子数目,若没有则输出0。
      9 
     10 1.直线路径:每只青蛙总是沿着一条直线跳跃稻田
     11 2.相同间距:且每次跳跃的距离都相同
     12 3.有进有出:而青蛙总是从稻田的一侧跳进稻田, 然后沿着某条直线穿越稻田, 从另一侧跳出去
     13 4.多项干扰:可能会有多只青蛙从稻田穿越
     14 问题: 在各条青蛙行走路径中, 踩踏水稻最多的那一条上, 有多少颗水稻被踩踏
     15 
     16 输入
     17      6 7    //6行7列
     18      14    //被踩的数量14棵
     19      2     1          //稻子的坐标
     20      3     4
     21      5     3...   (总共14个)
     22      
     23      6 7
     24      14
     25      2 1
     26      2 3
     27      2 5
     28      2 6
     29      2 7
     30      3 4
     31      4 2
     32      6 1
     33      6 2
     34      6 3
     35      6 4
     36      6 5
     37      6 6
     38      6 7
     39     
     40      
     41 输出
     42      7     (单只青蛙踩最多的步数,没有输出为0)
     43 */
     44 
     45 /*
     46 分析:
     47 解法一:
     48 枚举每一条路径的情况, 起点可能性*方向可能性*步长可能性=非常多(不可取)
     49 起始点:5000 方向:5000  步长:5000  总复杂度5000^3,不得行
     50 解法二:
     51 (1)、 
     52 确定前两颗被踩踏的坐标,起始点,方向,步长就都确定了
     53 设坐标为(X1,Y1),(X2,Y2),则两者之间的为间隔dX=X2-X1,dY=Y2-Y1;
     54 (2)、
     55 要求第一点的前一点要在稻田外,若不在,则第一点不满足第一点
     56 第三点则要求在稻田内,最后一点的后面一点要落在稻田外
     57 设坐标(X0,Y0),(X3,Y3);X0=X1-dX,Y0=Y1-dY;Xi=X1+i*dX,Yi=Y1+i*dY;(i>=3)
     58 (3)、
     59 猜测的过程中一定要尽快的排除错误!当满足如下条件的时候,就要排除最先选取的两点了:
     60 a,青蛙不能经过一跳从稻田外跳到第一点上去;
     61 b,按照第一点和第二点确定步长,从第一点出发,青蛙最多经过(MAXSTEPS-1)步,就会跳跃到稻田之外;
     62 MAXSTEPS是当前已经找到的最好的答案。
     63 (4)、
     64 选取合适的数据结构:
     65 关于被踩踏的水稻坐标最好采用单个变量的形式,简单清晰,此处采用结构体表示坐标;
     66 struct Plant{
     67 int x,y;//x,y分别表示水稻的行号和列号
     68 }
     69 (5)、
     70 猜测一条行走路径,需要从当前位置(X,Y)出发时,判断(X+dX,Y+dY)位置的水稻是否被踩踏;
     71 先采用sort()函数对plants中的元素排序,再用binary_search()从中查找元素(X+dX,Y+dY)。
     72 */
     73 
     74 #include <iostream>
     75 #include <cstdlib>
     76 #include <algorithm> 
     77 using namespace std;
     78 
     79 int r,c,n;
     80 struct PLANT{ //记录被践踏的水稻 
     81     int x,y;
     82 };
     83 PLANT plants[5001];
     84 PLANT plant;
     85 
     86 int searchPath(PLANT secPlant,int dX,int dY);
     87 
     88 int main(){
     89     freopen("3in.txt","r",stdin); 
     90     int i,j,dX,dY,pX,pY,steps,max=2;
     91     //行数和列数,x方向是上下,y方向是左右
     92     scanf("%d %d",&r,&c);
     93     
     94     scanf("%d",&n);
     95     for(i=0;i<n;i++){
     96         scanf("%d %d",&plants[i].x,&plants[i].y);
     97     } 
     98     //将水稻按x坐标从小到大排序,x坐标相同按y从小到大排序 
     99     sort(plants,plants+n);
    100     for(i=0;i<n-2;i++) //plants[i]是第一个点
    101         for(j=i+1;j<n-1;j++){ //plants[j]是第二个点
    102             dX=plants[j].x-plants[i].x; //dX表示x方向上面的间距 
    103             dY=plants[j].y-plants[i].y; //dy表示y方向上面的间距 
    104             pX=plants[i].x-dX; //pX表示选的第一个点的前一个点的横坐标 
    105             pY=plants[i].y-dY; //pY表示选的第一个点的前一个点的纵坐标
    106             
    107             if(pX<=r&&pX>=1&&pY<=c&&pY>=1)
    108                 continue;
    109             /*
    110             第一个的前一个点在稻田里,
    111             说明第一个点不是第一个点 
    112             也说明本次选的第二点导致的x方向步长不合理(太小) 
    113             取下一个点作为第二点 
    114             */ 
    115             if(plants[i].x+(max-1)*dX>r) //第二步在田外,说明选取不合适,重新选 
    116                 break;
    117             /*
    118             x方向过早越界,说明本次选的第二点不成立
    119             如果换下一个点作为第二点,x方向步长只会更大,更不成立
    120             所以应该认为本次选的第一点必然是不成立的,
    121             那么取下一个点作为第一点再试 
    122             也是因为x方向是从小到大排序,y方向没怎么排序 
    123             */
    124             pY=plants[i].y+(max-1)*dY;
    125             if(pY>c||pY<1)
    126                 continue; //y方向过早越界了,应该换一个点作为第二点再试
    127                 
    128             steps=searchPath(plants[j],dX,dY);
    129             //看看从这两点出发,一共能走几步
    130             if(steps>max) max=steps; 
    131         } 
    132     
    133     if(max==2) max=0;
    134     printf("%d
    ",max); 
    135     
    136     return 0;
    137 }
    138 /*
    139 重载小于号
    140 将水稻按x坐标从小到大排序,x坐标相同按y从小到大排序  
    141 */ 
    142 bool operator <(const PLANT &p1,const PLANT &p2){  
    143     if(p1.x==p2.x)
    144         return p1.y<p2.y;
    145     return p1.x<p2.x;
    146 }
    147 //判断从 secPlant点开始,步长为dx,dy,那么最多能走几步 
    148 int searchPath(PLANT secPlant,int dX,int dY){
    149     PLANT plant; //中间节点 
    150     int steps; //最多能走的步数 
    151     plant.x=secPlant.x+dX; //下一个点的横坐标 
    152     plant.y=secPlant.y+dY; //下一个点的纵坐标 
    153     steps=2; //我们选了两个点,之前已经有两步了,我是从选取的第二个点开始的,所以之前已经有两步 
    154     while(plant.x<=r&&plant.x>=1&&plant.y<=c&&plant.y>=1){ //如果下一个点不越界 
    155         //二分查找函数,若用到其他数据结构则需使用"operator<",是bool类型   
    156         if(!binary_search(plants,plants+n,plant)){ //并且plant这个点(也就是下一个点)在plants中 
    157             //每一步都必须踩倒水稻才算合理,否则这就不是一条行走的路径
    158             steps=0;
    159             break; 
    160         }
    161         // 步数加1,并且继续寻找下一个点 
    162         plant.x+=dX;
    163         plant.y+=dY;
    164         steps++;
    165     }
    166     return (steps);
    167 }
  • 相关阅读:
    POJ2407:Relatives(欧拉函数) java程序员
    POJ1664:放苹果(搜索) java程序员
    关于android中数据库的创建以及基础的增删改查的相应操作
    家庭版记账本app开发进度。开发到现在整个app只剩下关于图表的设计了,具体功能如下
    在tap的碎片上与活动进行绑定实现点击事件(日期时间选择以及按钮跳转时间)
    使用tap、Fragment等相关相关知识点。实现类似微信的界面
    android学习相关intent和fragment的先关知识点
    家庭记账本app进度之关于tap的相关操作1
    家庭版记账本app进度之关于listview显示账单,并为其添加点击事件
    家庭版记账本app进度之编辑框组件
  • 原文地址:https://www.cnblogs.com/Renyi-Fan/p/6926974.html
Copyright © 2020-2023  润新知