枚举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 }