题目描述:http://poj.org/problem?id=1054
本题使用枚举的思想。但是单纯枚举解得范围太大,我们需要在对可能的范围进行剪枝。我们可以先选中一个点作为起始点,另一个点做第二个点,这样就可以确定一条直线。再对这条直线是否符合剪枝条件进行考察,先来可以下剪枝的条件有哪些:
1、既然选中了起始点,那么根据其与第二个点的步长,可以知道上一步一定是在田外的,否则就不能成为起始点。
2、按题目中要求,你只关心大于等于三条稻子被压倒的路径,那么如果第三个点已经在田外,则也不符合情况。
3、如果从第一个点开始,走当前maxSteps-1步,到了田外面,那么这条路径一定也是不符合情况的(maxSteps为当前最长路径)。
基本思路:
1、写一个Plant类,代表被踩到的稻子。其中成员变量包括此稻子的x座标和y座标。
2、对被踩到的稻子按照先x轴再y轴的标准,从小到大排序。从而后面再确定某一步是否被踩到时,可以使用二分查找。
3、对第一个点和第二个点的组合进行枚举,在枚举过程中进行剪枝。
AC代码如下:
//POJ 1054
package week1;
import java.util.*;
public class The_Troublesome_frog {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int r = sc.nextInt();
int c = sc.nextInt();
int n = sc.nextInt();
Plant[] plants = new Plant[n];
//初始化
for(int i=0; i<n; i++){
plants[i] = new Plant();
plants[i].x = sc.nextInt();
plants[i].y = sc.nextInt();
}
Arrays.sort(plants);
int maxSteps = 2;
//选择plant[i]为第一个点,plants[j]为第二个点
for(int i=0; i<n;i++){
for(int j=i+1; j<n; j++){
int dx = plants[j].x - plants[i].x;
int dy = plants[j].y - plants[i].y;//在x和y方向上求得青蛙每一步的长度
int px = plants[i].x - dx;
int py = plants[i].y - dy;//求按照此步长,第一步之前的一步的位置
if(px >= 1 && px <= r && py >= 1 && py <= c)
continue;
//如果第一点的前一点在稻田内,说明第二点选的不合适,换一个点做第二点
int xMax = plants[i].x + (maxSteps - 1) * dx;
if(xMax > r)
break;
//未达到目前最长步数-1就出了稻田,说明这条路无法成为当前最长
//因为x是进过排序的,因此换第二个点只能使得出稻田更快,因此此时要换第一个点
int yMax = plants[i].y + (maxSteps - 1) * dy;
if(yMax > c || yMax < 1)
continue;
//Y方向过早越界,换第二个点
int steps = searchPath(plants[j], plants, dx, dy, r, c);
if (steps > maxSteps){
maxSteps = steps;
}
}
}
if(maxSteps == 2) maxSteps = 0;
System.out.println(maxSteps);
sc.close();
}
public static int searchPath(Plant secPlant, Plant[] plants, int dx, int dy, int r, int c){
Plant tmp = new Plant();//表示当前位置
tmp.x = secPlant.x + dx;
tmp.y = secPlant.y + dy;
int steps = 2;
while(tmp.x <= r && tmp.x >=1 && tmp.y <= c && tmp.y >= 1){
//当下一步在稻田内时,查找下一步的座标是否在Plants[]中
int index = Arrays.binarySearch(plants, tmp);
if( index < 0){
steps = 0;
break;
}
steps++;
tmp.x += dx;
tmp.y += dy;
}
return steps;
}
}
class Plant implements Comparable<Plant>{
int x;
int y;
public Plant(){
this.x = 0;
this.y = 0;
}
public int compareTo(Plant p) {
if(this.x > p.x){
return 1;
}
else{
if(this.x < p.x) return -1;
else{
if(this.y > p.y) return 1;
else
{
if(this.y < p.y)
return -1;
else return 0;
}
}
}
}
}