pku_oj: w11-03讨厌的青蛙(C++枚举算法)

Posted laideng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了pku_oj: w11-03讨厌的青蛙(C++枚举算法)相关的知识,希望对你有一定的参考价值。

问题描述:

有一个矩形稻田,每天晚上,青蛙会从一侧跳进稻田从而踩坏稻子,规定:每只青蛙总沿着一条直线跳跃,且每只青蛙每次跳跃距离相同(不同青蛙的蛙跳步长不同 ,不同青蛙的蛙跳 方向可能不同)

稻田里的稻子组成一个栅格, 每棵稻子位于一个格点上 ,而青蛙总是从稻田的一侧跳进稻田, 然后沿着某条直线穿 越稻田, 从另一侧跳出去,如图:技术图片

 

农民想知道那只踩了最多稻子的青蛙的跳跃轨迹,请给出该轨迹上踩的稻子数(规定一条路径上稻子数至少为3)

 

输入:

 第一行上两个整数R, C, 分别表示稻田中水稻的行数和 列数, 1≤R, C≤5000 ;第二行是一个整数N, 表示被踩踏的水稻数量, 3≤N≤5000 ;在剩下的N行中, 每行有两个整数, 分别是一颗被踩踏水 稻的行号(1~R)和列号(1~C), 两个整数用一个空格隔开 ;且每棵被踩踏水稻只被列出一次

输出:

如果在稻田中存在青蛙行走路径, 则输出包含最多水稻 的青蛙行走路径中的水稻数量, 否则输出0

示例:

技术图片

 

 

分析:

首先,自然想到枚举算法,由于稻田是有限的,或者说,被破坏的稻子数量是有限的(不超过5000),对于一条路径,我们如何确定它?从三个方面考虑:起始点,方向,步长。似乎可行,但简单分析可以知道,最坏情况下,需要付出5000*5000*5000的代价,这不能令人满意。因此,必须设法缩小解空间。

如果我们从踩坏的稻子序列中,拿出两个,假设一个是第一个跳跃点,一个是第二个跳跃点。在这种假设下,我们得到跳跃步长(作减法即可,注意x、y两个方向上的向量分解),然后根据一些必要条件,判断是否是可能解,如果不是则提前从解空间中删除该解,进入下一个枚举。如果满足必要条件,则需要计算该走法的情况下的踩坏的稻子数,如果比既定的max大,则更新Max,否则继续下一轮枚举。

必要条件说明:

根据第一个点坐标 和 计算得到的步长,计算第一个点的前一个点,是否落在稻田内,如果是,则假设不正确,continue

为了避免无效计算,可根据假定的max,从x和y两个角度判断是否可能比max大,如果提早越界,则作相应处理,因为不可能是有效解(说明:本算法中对x作了排列,因此这不是由第二个点导致的,而是第一个点的问题)

 

代码(c++):

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <algorithm>
 4 using namespace std;
 5 int r, c, n;
 6 struct PLANT 
 7     int x, y;
 8 ;
 9 PLANT plants[5001];
10 
11 int searchPath(PLANT, int, int);
12 
13 int main()
14 
15     freopen("input2.txt", "r", stdin);
16     int max = 2, steps;
17     scanf("%d %d %d", &r, &c, &n);
18     for (int i = 0; i < n; ++i) 
19         scanf("%d %d", &plants[i].x, &plants[i].y);
20     //input end
21     sort(plants, plants + n);
22     for (int i = 0; i < n-2; ++i)
23         for (int j = i + 1; j < n-1; ++j) 
24             int dX = plants[j].x - plants[i].x;
25             int dY = plants[j].y - plants[i].y;
26             int pX = plants[i].x - dX;
27             int pY = plants[i].y - dY;
28             if (pX >= 1 && pX <= r && pY >= 1 && pY <= c)
29                 continue;
30             if (plants[i].x + (max - 1)*dX > r)    
31                 break;
32             pY = plants[i].y + (max - 1)*dY;
33             if (pY > c || pY < 1)
34                 continue;
35             steps = searchPath(plants[j], dX, dY);
36             if (steps > max)
37                 max = steps;
38         
39     if (max == 2)
40         max = 0;
41     printf("%d\\n", max);
42 
43 
44 int searchPath(PLANT p, int dX, int dY)
45 
46     PLANT q;
47     q.x = p.x + dX;
48     q.y = p.y + dY;
49     int steps = 2;
50     while (q.x <= r && q.x >= 1 && q.y <= c && q.x >= 1) 
51         if (!binary_search(plants, plants + n, q)) 
52             steps = n;
53             break;
54         
55         q.x += dX;
56         q.y += dY;
57         steps++;
58     
59     return steps;
60 
61 
62 bool operator<(const PLANT & p1, const PLANT & p2)
63 
64     if (p1.x == p2.x) 
65         return p1.y < p2.y;
66     
67     return p1.x < p2.x;
68 

 

以上是关于pku_oj: w11-03讨厌的青蛙(C++枚举算法)的主要内容,如果未能解决你的问题,请参考以下文章

pku_oj: W11-02熄灯问题(C++)

枚举_百炼 2812 讨厌的青蛙

pku_oj: 1681Painter's Problem(画家问题)(C++)

青蛙过河问题

DP青蛙过河

NOIP2005提高组——青蛙过河