`

1054(枚举)

阅读更多

1054:The Troublesome Frog

总时间限制:
5000ms
内存限制:
100000kB
描述
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 have been flattened, you want to identify the path of the frog which did the most damage. A frog always jumps through the paddy in a straight line, with every hop the same length:

Your rice paddy has plants arranged on the intersection points of a grid as shown in Figure-1, and the troublesome frogs hop completely through your paddy, starting outside the paddy on one side and ending outside the paddy on the other side as shown in Figure-2:

Many frogs can jump through the paddy, hopping from rice plant to rice plant. Every hop lands on a plant and flattens it, as in Figure-3. Note that some plants may be landed on by more than one frog during the night. Of course, you can not see the lines showing the paths of the frogs or any of their hops outside of your paddy ?for the situation in Figure-3, what you can see is shown in Figure-4:

From Figure-4, you can reconstruct all the possible paths which the frogs may have followed across your paddy. You are only interested in frogs which have landed on at least 3 of your rice plants in their voyage through the paddy. Such a path is said to be a frog path. In this case, that means that the three paths shown in Figure-3 are frog paths (there are also other possible frog paths). The vertical path down column 1 might have been a frog path with hop length 4 except there are only 2 plants flattened so we are not interested; and the diagonal path including the plants on row 2 col. 3, row 3 col. 4, and row 6 col. 7 has three flat plants but there is no regular hop length which could have spaced the hops in this way while still landing on at least 3 plants, and hence it is not a frog path. Note also that along the line a frog path follows there may be additional flattened plants which do not need to be landed on by that path (see the plant at (2, 6) on the horizontal path across row 2 in Figure-4), and in fact some flattened plants may not be explained by any frog path at all.

Your task is to write a program to determine the maximum number of landings in any single frog path (where the maximum is taken over all possible frog paths). In Figure-4 the answer is 7, obtained from the frog path across row 6.
输入
Your program is to read from standard input. The first line contains two integers R and C, respectively the number of rows and columns in your rice paddy, 1 <= R,C <= 5000. The second line contains the single integer N, the number of flattened rice plants, 3 <= N <= 5000. Each of the remaining N lines contains two integers, the row number (1 <= row number <= R) and the column number (1 <= column number <= C) of a flattened rice plant, separated by one blank. Each flattened plant is only listed once.
输出
Your program is to write to standard output. The output contains one line with a single integer, the number of plants flattened along a frog path which did the most damage if there exists at least one frog path, otherwise, 0.
样例输入
6 7
14
2 1
6 6
4 2
2 5
2 6
2 7
3 4
6 1
6 2
2 3
6 3
6 4
6 5
6 7
样例输出
7
 翻译:
问题描述:在韩国,有一种小的青蛙。每到晚上,这种青蛙会跳越稻田,从而踩踏稻子。农民在早上看到被踩踏的稻子,希望找到造成最大损害的那只青蛙经过的路径。
每只青蛙总是沿着一条直线跳越稻田,而且每次跳跃的距离都相同。
不同的青蛙有不同的跳跃距离,不同的跳跃方向。
如下图所示,稻田里的稻子组成一个栅格,每棵稻子位于一个格点上。而青蛙总是从稻田的一侧跳进稻田,然后沿着某条直线穿越稻田,从另一侧跳出去
如下图所示,可能会有多只青蛙从稻田穿越。青蛙的每一跳都恰好踩在一棵水稻上,将这棵水稻拍倒。有些水稻可能被多只青蛙踩踏。当然,农民所见到的是图4中的情形,并看不到图3中的直线,也见不到别人家田里被踩踏的水稻。
根据图4,农民能够构造出青蛙穿越稻田时的行走路径,并且只关心那些在穿越稻田时至少踩踏了3棵水稻的青蛙。因此,每条青蛙行走路径上至少包括3棵被踩踏的水稻。而在一条青蛙行走路径的直线上,也可能会有些被踩踏的水稻不属于该行走路径
①不是一条行走路径:只有两棵被踩踏的水稻
②是一条行走路径,但不包括(2,6)上的水道
③不是一条行走路径:虽然有3棵被踩踏的水稻,但这三棵水稻之间的距离间隔不相等
 问,给定一块被踩坏的稻田,求可能的最长的蛙路上被踩坏的作物的数目。
例如,图4的答案是7,因为第6行上全部水稻恰好构成一条青蛙行走路径
输入:
第一行整数R和C,稻田的行数和列数
第二行整数N,表示被踩坏的作物总数。
后续N行,每行两个整数i,j为被 踩坏的作物的行和列的位置: 1<=i<=R, 1<=j<=C。
每个被踩坏的作物只出现一次。
输出:
单个整数
 -- 表示最长可能蛙路上踩坏的作物数目
 
问题分析:
1.在给出的n个点中找出一些点的序列来使得每一个点相对于上一个点的坐标都是一个相同的常量
2.“第一个点减去这个常量”和“最后一个点加上这个常量”后均落在方格的外面。
3.先对这些点按坐标排序
4.然后依次循环出要求得序列中的第一个和第二个点,这样就知道后一个点相对于前一个点的坐标
是多少了
5.依次用第二个点加上这个坐标求出第三个点
6.第三个点加上这个坐标求出第四个点等等
7.判断求出来的第三四个点是否在给定的点内
8.由于每个点的上一个点或下一个点最多只能有n种选择,故一个短最多属于n条不同的路
9.对于某个确定的点来说,它的所有可能的下一个需要判断的点至多有n个。这样因为判断一个点在不在给定的点内只需要O(1)的复杂度,所以只需要O(n2)的时间就可以得出问题的解答。
10.由于这个算法需要一个r*c的表来保存点在方格中的存在状态,故空间复杂度为O(n2)。
11.二分查找
函数名: bsearch
功 能: 二分法搜索
用 法: void *bsearch(const void *key, const void *base, size_t nelem, size_t width, int(*fcmp)(const void *, const *));
语法:
#include <stdlib.h> void *bsearch( const void *key, const void *buf, size_t num, size_t size, int (*compare)(const void *, const void *) ); 
参数:第一个:要查找的关键字。第二个:要查找的数组。第三个:指定数组中元素的数目。第四个:每个元素的长度(以字符为单位)。第五个:指向比较函数的指针。
功能: 函数用折半查找法在从数组元素buf[0]到buf[num-1] 匹配参数key。如果函数compare 的第一个参数小于第二个参数,返回负值;如果等于返回零值;如果大于返回正值。数组buf 中的元素应以升序排列。函数bsearch()的返回值是指向匹配项,如果没有发现匹配项,返回NULL
 
 
解决方案一:G++
 
 
#include<cstdio>
#include<cstdlib>
using namespace std ;
int r,c,n ;
struct PLANT{
 int x,y ;
};
PLANT plants[5001] ;
PLANT plant ;
int myCompare(const void*x,const void*y)
{    //按照x值由小到大排序
    //x相同时,按照y值由小到大到排列
    PLANT *a,*b;
    a=(PLANT*)x;
    b=(PLANT*)y;
    if(a->x==b->x) return (a->y-b->y) ;
    return a->x-b->x ;
}
int searchPath(PLANT secPlant,int dx,int dy)
{  //从secPlant点开始,步长为dx,dy,最多能走几步
    int steps ;
    plant.x = secPlant.x + dx ;
    plant.y = secPlant.y + dy ;
    steps = 2 ;
    while(plant.x<=r&&plant.x>=1&&plant.y<=c&&plant.y>=1)
    {
        if(!bsearch(&plant,plants,n,sizeof(PLANT),myCompare))//调用二分查找
        { //每一步必须踩到水稻
           steps = 0 ;
           break ;
        }
       plant.x += dx ;
       plant.y += dy ;
         steps++ ;
    }

   return steps ;
}
int main()
{
 int i,j,dX,dY,pX,pY,steps,max=2;
 scanf("%d%d",&r,&c);//稻田的长和宽
 scanf("%d",&n);//共有多少水稻被踩踏
 for(i=0;i<n;i++)
  scanf("%d%d",&plants[i].x,&plants[i].y) ;
  qsort(plants,n,sizeof(PLANT),myCompare) ;
  for(i=0;i<n-2;i++)//plants[i]是第一个点
   for(j=i+1;j<n-1;j++){//plants[j]是第二个点
   dX = plants[j].x - plants[i].x ;
   dY = plants[j].y - plants[i].y ;
   pX = plants[i].x - dX ;
   pY = plants[i].y - dY ;
   if(pX<=r&&pX>=1&&pY<=c&&pY>=1)
          continue ;//第一点的前一点还在稻田里,说明本次选的第二点不合理
                    //再选择另外的点在作为第二个点
   if(plants[j].x+(max-1)*dX>r)
       break ; //x方向过早越界,第二点选择不成立
    //如果继续选择下一个点作为第二点,x步长方面的增长
    //只会更大,所以果断要换第一个点
    pY = plants[j].y + (max-1)*dY ;
    if(pY>c||pY<1)
        continue ;//越界
    steps = searchPath(plants[j],dX,dY);//看看从这两点出发能走几步
    if(steps>max) max = steps ;
   }
   if(max==2) max = 0 ;
   printf("%d\n",max) ;
   return 0 ;
}
 

解决方案二:Java   

package dsa;

import java.util.Scanner;

public class Demo14 {
  int r,c,n;
  Plant plants[] = new Plant[5001];
  public static void main(String[] args) {
	new Demo14().test() ;
  }
	public void test()
	{
		Scanner sc = new Scanner(System.in);
		int i,j,dX,dY,pX,pY,steps,max=2; 
		r = sc.nextInt() ;
		c = sc.nextInt() ;
		n = sc.nextInt() ;
		for(i=0;i<n;i++)
		{
			plants[i] = new Plant() ;
			plants[i].x = sc.nextInt() ;
			plants[i].y = sc.nextInt() ;
		}
	 Qsort() ;
//	 for(i=0;i<n;i++)
//	 {
//		 System.out.println(plants[i].x+"-----"+plants[i].y);
//	 }
		for(i=0;i<n-2;i++){
			for(j=i+1;j<n-1;j++)
			{
				dX = plants[j].x - plants[i].x ;
				dY = plants[j].y - plants[i].y ;
				pX = plants[i].x - dX ;
				pY = plants[i].y - dY ;
			  if(pX<=r&&pX>=1&&pY<=c&&pY>=1)
			          continue ;
			  
			  if(plants[j].x+(max-1)*dX>r)
			       break ; 
			   
			   pY = plants[j].y + (max-1)*dY ;
			     if(pY>c||pY<1)
			        continue ;
			  
			  steps = searchPath(plants[j],dX,dY) ;
			  //  System.out.println(steps) ;
			    if(steps>max) max = steps ;
			}
	}
		if(max==2) max = 0 ;
		System.out.println(max);
	}
	public int searchPath(Plant secPlant,int dX,int dY)
	{  //从secPlant点开始,步长为dx,dy,最多能走几步
	    int steps ;
	    Plant plant = new Plant();
	    plant.x = secPlant.x + dX ;
	    plant.y = secPlant.y + dY ;
	    steps = 2 ;
	    boolean b ;
	    while(plant.x<=r&&plant.x>=1&&plant.y<=c&&plant.y>=1)
	    {   
	         b 	= bsearch(plant);
	    	//System.out.println(b) ;
	        if(!b)
	        { //每一步必须踩到水稻
	           steps = 0 ;
	           break ;
	        }
	       plant.x += dX ;
	       plant.y += dY ;
	         steps++ ;
	    }
	    
	   // System.out.println(steps) ;
	    return steps ;
	    
	}
	/**
	 * 二分查找
	 */
	public boolean bsearch(Plant plant)
	{  
		int low = 0;
		int high = n-1 ;
		int mid ;
		//System.out.println("开始二分查找") ;
		while(low<=high)
		{
		mid = (low+high)/2 ;
		 if(plant.x==plants[mid].x)
		 { 
			 if(plant.y==plants[mid].y)
			 {
			 return true ;
			 }else if(plant.y<plants[mid].y) high = mid -1 ;
			 else  low = mid +1 ;
		 }else if(plant.x<plants[mid].x) high = mid -1 ;
		 else low = mid +1 ;
		}
		return false ;
	}
	public void Qsort()
	{
		int i,j;
		for(i=0;i<n;i++)
			for(j=i+1;j<n;j++)
			{
			if(	plants[i].x==plants[j].x)
			{
				if(plants[i].y>plants[j].y)
				{
					Plant temp = new Plant();
					temp = plants[i] ;
				    plants[i] =	plants[j] ;
				    plants[j] = temp ;
				}
			}
			if(	plants[i].x>plants[j].x)
			{   
				Plant temp = new Plant();
				temp = plants[i] ;
			    plants[i] =	plants[j] ;
			    plants[j] = temp ;
			}
		}
	//	System.out.println("排序成功") ;
	}
	class Plant{
		int x ;
		int y ;
	}
}

因为java代码中的函数都是自己写的,所以有点复杂,不过还是强免ac了。哈哈!

 
分享到:
评论

相关推荐

    POJ1054讨厌的青蛙

    POJ1054讨厌的青蛙,利用枚举算法解题,值得一做。

    北京大学acm题库 题目分类

    枚举是ACM题库中的一个基础算法,包括暴力枚举、递归枚举等。相关题目有:1012,1046, 1387, 1411, 2245, 2326, 2363, 2381,1054(剪枝要求较高),1650 (小数的精度问题) 数据结构的典型算法 数据结构的...

    北大ACM 题目分类

    其中,1054号题特别提到了剪枝技术的重要性,这是在大规模数据集上进行有效枚举的关键。通过学习这些题目,参赛者可以学会如何在避免穷尽搜索的同时找到正确答案,这对于提高算法效率至关重要。 #### 数据结构的...

    杭州电子大学acm题型分类

    - 题目1010、1050、1051、1052、1053、1054、1055、1057、1060、1061、1070和1075涉及贪心策略,需要找出局部最优解来构建全局最优解。 5. **数据结构**: - 题目1022提到了栈的应用,可能是要求使用栈解决逆序...

    acm poj300题分层训练

    6. **更复杂的动态规划**:poj1191、poj1054等题目增加了动态规划的难度,引入了记录状态的DP和树型DP。 7. **数学**:poj1286、poj2409等继续深入组合数学,poj1226、poj1961等训练了KMP算法,poj3440、poj3071等...

    ACMer需要掌握的算法讲解 (2).docx

    * 枚举算法:POJ1753、POJ2965 * 贪心算法:POJ1328、POJ2109、POJ2586 * 递归和分治法 * 递推算法 * 构造法:POJ3295、POJ3259、POJ1062、POJ2253、POJ1125、POJ2240 * 最小生成树算法:prim、kruskal、POJ1789、...

    poj题目分类

    * 枚举法:通过枚举所有可能的解来解决问题,例如 poj1753、poj2965。 * 贪心算法:通过选择当前最优的解决方案来解决问题,例如 poj1328、poj2109、poj2586。 * 递归和分治法:通过将问题拆分成小问题来解决,...

    杭电acm分类

    **1054-1055 二分匹配** 二分匹配是一种解决图论中匹配问题的有效算法,适用于解决特定类型的匹配问题。 **1064 简单题** 尽管标记为简单,但在ACM竞赛中,任何题目的解都需要严谨的逻辑和算法设计。 **1075 字典...

    poj训练计划.doc

    - 枚举:通过列举所有可能的情况来解决问题,例如`poj1753, poj2965`。 - 贪心算法:在每一步选择中都采取在当前状态下最好或最优的选择,如`poj1328, poj2109, poj2586`。 - 分治法:将一个复杂的问题分成两个或...

    二分匹配题集

    20. **Strategic Game (HDU 1054)** - **知识点**:最小点覆盖问题。 - **解题思路**:使用最大匹配算法找到最大匹配,然后利用Konig定理计算最小点覆盖。 21. **Swap (HDU 2819)** - **知识点**:行列匹配+...

    ZJU_ACM_All_Anwer 搞编程的都知道的浙江大学A 题库.本书 集了所有经 Z 题解集,集合并附 Mathimaticsumerical algorithms 数值算法

    1489 2^x mod n = 1 简单题,应该有好算法,不过枚举就可以过…… 1503 One Person "The Price is Right" 简单题,POI Eggs的翻版 1512 Water Treatment Plants 简单题,组合计数 1526 Big Number 简单题,不过O(1...

    浙江大学ACM题解/ZJU 题型分类

    1489 2^x mod n = 1 简单题,应该有好算法,不过枚举就可以过…… 1503 One Person "The Price is Right" 简单题,POI Eggs的翻版 1512 Water Treatment Plants 简单题,组合计数 1526 Big Number 简单题,不过O(1...

    hdu题目分类

    - **解题思路**: 通过枚举检查所有可能的情况。 31. **1037 Guardian of Decency 图论:匈牙利算法求二分图的最大匹配** - **知识点**: 匈牙利算法、最大匹配。 - **描述**: 找到二分图的最大匹配。 - **难度...

    acm题目分类

    - **1099**: 数学题,可能涉及到模拟题或者枚举法解决问题。 - **1100**: 数学题,具体细节未知。 - **1108**: 数学题,具体细节未知。 - **1110**: 数学题,具体细节未知。 - **1112**: 数学题,具体细节未知。 - *...

    ASP.NET4高级程序设计(第4版) 3/3

    4.3.4 枚举 110 4.3.5 颜色 110 4.3.6 字体 111 4.3.7 焦点 12 4.3.8 默认按钮 113 4.3.9 可滚动面板 114 4.3.10 处理Web控件事件 114 4.4 List控件 116 4.4.1 Selectable列表控件 117 4.4.2 ...

Global site tag (gtag.js) - Google Analytics