首页 > 代码库 > 枚举3--讨厌的青蛙

枚举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\n",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 }

 

枚举3--讨厌的青蛙