枚举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 }
时间: 2024-10-16 23:19:29

枚举3--讨厌的青蛙的相关文章

枚举_百炼 2812 讨厌的青蛙

1 #define _CRT_SECURE_NO_WARNINGS 2 #include <stdio.h> 3 #include <math.h> 4 #include <algorithm> 5 #include <stdlib.h> 6 #include <vector> 7 #include <map> 8 #include <queue> 9 #include <string> 10 #include

IOI2002 POJ1054 The Troublesome Frog 讨厌的青蛙 (离散化+剪枝)

Description In Korea, the naughtiness of the cheonggaeguri, a small frog, is legendary. This is a well-deserved reputation, because the frogs jump through your rice paddy at night, flattening rice plants. In the morning, after noting which plants hav

算法学习 -- 枚举

在学习枚举算法之前,首先问有关枚举的几个问题 1. 为什么要进行枚举? 2. 需要对哪些对象进行枚举? 3. 如何进行枚举? 4. 枚举的结束条件是什么? 现在针对两个使用枚举算法的实例对以上问题进行分析. 实例一:熄灯问题 给定一个5×6的棋盘,上面有灯,每个灯都有各自的按钮,每个按钮按下去都会使其自己和周围的上下左右四盏灯改变(原来熄灭的变亮,原来亮的变灭),如何操作按钮使这个棋盘上所有灯都熄灭. 实例二:青蛙问题 一个5000×5000的稻田,有很多青蛙从这个稻田上跳过,每只青蛙跳过的步长

动态规划--青蛙跳

Description 在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧.在桥上有一些石子,青蛙很讨厌踩在这些石子上.由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点:0,1,……,L(其中L是桥的长度).坐标为0的点表示桥的起点,坐标为L的点表示桥的终点.青蛙从桥的起点开始,不停的向终点方向跳跃.一次跳跃的距离是s到t之间的任意正整数(包括s,t).当青蛙跳到或跳过坐标为L的点时,就算青蛙已经跳出了独木桥. 题目给出独木桥的长度L,

NOIP 2005 青蛙过河

做题记录:2016-08-10 21:58:09 题目描述 在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧.在桥上有一些石子,青蛙很讨厌踩在这些石子上.由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点:0,1,……,L(其中L是桥的长度).坐标为0的点表示桥的起点,坐标为L的点表示桥的终点.青蛙从桥的起点开始,不停的向终点方向跳跃.一次跳跃的距离是S到T之间的任意正整数(包括S,T).当青蛙跳到或跳过坐标为L的点时,就算青蛙已经跳出

POJ 1054 The Troublesome Frog(枚举+剪枝)

题目链接 题意 :给你r*c的一块稻田,每个点都种有水稻,青蛙们晚上会从水稻地里穿过并踩倒,确保青蛙的每次跳跃的长度相同,且路线是直线,给出n个青蛙的脚印点问存在大于等于3的最大青蛙走的连续的脚印个数. 思路 : 暴力了一下,顺便剪剪枝就可以过.... 1 //POJ1054 2 #include <stdio.h> 3 #include <string.h> 4 #include <iostream> 5 #include <algorithm> 6 7

hlg1186青蛙过河【dp】

题意:在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧.在桥上有一些石子,青蛙很讨厌踩在这些石子上.由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点:0,1,……,L(其中L是桥的长度).坐标为0的点表示桥的起点,坐标为L的点表示桥的终点.青蛙从桥的起点开始,不停的向终点方向跳跃.一次跳跃的距离是s到t之间的任意正整数(包括s,t).当青蛙跳到或跳过坐标为L的点时,就算青蛙已经跳出了独木桥. 题目给出独木桥的长度L,青蛙跳跃的距离范围

poj 1061青蛙的约会

青蛙的约会 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 90083   Accepted: 16257 Description 两仅仅青蛙在网上相识了,它们聊得非常开心,于是认为非常有必要见一面.它们非常高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止.但是它们出发之前忘记了一件非常重要的事情,既没有问清楚对方的特征,也没有约定见面的详细位置.只是青蛙们都是非常乐观的,它们认为仅仅要一直朝着某个方

ooj 1066 青蛙过河DP

http://121.249.217.157/JudgeOnline/problem.php?id=1066 1066: 青蛙过河 时间限制: 1 Sec  内存限制: 64 MB提交: 58  解决: 13[提交][状态][讨论版] 题目描述 在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧.在桥上有一些石子,青蛙很讨厌踩在这些石子上. 由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整数: 0,1,……,L(其中L是桥的长度). 坐标