poj1088(动态规划经典)

         题目链接:http://poj.org/problem?id=1088

        题目意思:滑雪问题,给一个二维数组,要求从中找出一点,从改点出发,可以向前、后、左、右四个方向滑动,但要求高度只能越来越低,求出这样一条路径最长的下降序列,输出经过的点的个数(max)。

        以下转自某以为大牛:

           

算法:开一个二维数组high记录每个点的高度,一个二维数组len记录每个点能搜索到的最长下降子序列的长度(初始值全为零),一个结构体数组note line[20000]记录每个点的坐标(x,y)和高度值 h.

先将每个点的记录信息保存在结构体数组中。然后以高度由低到高的顺序排序,初始状态下指针就位于结构体数组的起始位置。

接着顺序的扫描此结构体数组内的信息,因为已经排好序,所以高度是一次递增的,这样做的好处是只需要朝着一个方向搜索,而且还可以有效避免越界的问题。

当指针每指向一个结构体个体时,我们均可以找到该点在high数组里的位置,如果存在任意一个点,在它周围的四个方向上而且高度比该点大且这个任意点的最长下降子序列小于或等于该店的长度。那么这个任意点的最长下降子序列的长度就+1;

等到结构体数组扫描完成,再去遍历len这个二维数组,求出最大值即为所求;

代码:
      

#include<stdio.h>
#include<stdlib.h>
typedef struct
{
	int x;
	int y;
	int h;
}note;
note line[20000];
int high[120][120];
int len[120][120];
int cmp(const void *e1,const void *e2)
{
	if((*(note*)e1).h > (*(note*)e2).h)
		return 1;
	else 
		return -1;
}
void main()
{
	int i,j,k=-1,m,n,max=0;
	scanf("%d%d",&m,&n);
		for(i=1;i<=m;i++)
			for(j=1;j<=n;j++)
			{
				k++;
				scanf("%d",&high[i][j]);
				line[k].x=i;
				line[k].y=j;
				line[k].h=high[i][j];
			}
	qsort(line,m*n,sizeof(line[0]),cmp);
	for(i=0;i<m*n;i++)
	{
	if(high[line[i].x][line[i].y]<high[line[i].x+1][line[i].y]&&len[line[i].x][line[i].y]>=len[line[i].x+1][line[i].y])
		len[line[i].x+1][line[i].y]=len[line[i].x][line[i].y]+1;
    if(high[line[i].x][line[i].y]<high[line[i].x-1][line[i].y]&&len[line[i].x][line[i].y]>=len[line[i].x-1][line[i].y])
		len[line[i].x-1][line[i].y]=len[line[i].x][line[i].y]+1;
	if(high[line[i].x][line[i].y]<high[line[i].x][line[i].y+1]&&len[line[i].x][line[i].y]>=len[line[i].x][line[i].y+1])
		len[line[i].x][line[i].y+1]=len[line[i].x][line[i].y]+1;
	if(high[line[i].x][line[i].y]<high[line[i].x][line[i].y-1]&&len[line[i].x][line[i].y]>=len[line[i].x][line[i].y-1])
		len[line[i].x][line[i].y-1]=len[line[i].x][line[i].y]+1;
	}
	for(i=1;i<=m;i++)
		for(j=1;j<=n;j++)
		{
			if(max<=len[i][j])
				max=len[i][j];
		}
		printf("%d\n",max+1);
}


 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值