【DP动归】【DFS】POJ-1088 滑雪

题目链接:http://poj.org/problem?id=1088点击打开链接

题目描述:好吧,这熊孩纸要滑雪,他得从地图上高的地方往低的地方滑,可以滑向上下左右四个方向相邻的格,问最长路径多长?

题目里给出地图的,差不多酱紫:

5 3

2 10 2
1 2 2
2 5 6
3 4 7
1 9 8

5 5
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9



解题思路:先说dp的解题思路吧,我的代码是这样想的,用dp[ i ] [ j ] 表示从该点往下滑的最长路径。dp[ i ] [ j ]等于{[i-1][ j ] / [i][j-1] / [i+1][ j ] / [ i ][j+1]}这四个位置中比[ i ][ j ]高度低的之中dp值最大的一个dp[某][某]+1。如果这四个点都比[ i ][ j ]高度大,那么dp[ i ][ j ]=1。我们还需要用结构体来存地图,按高度给结构体排序,按升序得到每点的dp值。

我的代码:

我觉得test函数还是挺有必要的。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

struct node
{
    int x;
    int y;
    int h;
};

int R,C;
node grid[10100];
int dp[120][120];
int realmap[120][120];
int dx[]={0,0,1,-1},
    dy[]={1,-1,0,0};

bool cmp(node a,node b)
{
    return a.h<b.h;
}

void test()
{
    int i,j;
    for(i=0;i<R;i++)
    {
        for(j=0;j<C;j++)
            cout<<realmap[i][j]<<" ";
        cout<<endl;
    }
    cout<<endl;
    for(i=0;i<R*C;i++)
    {
        cout<<grid[i].x<<" "<<grid[i].y<<" "<<grid[i].h<<endl;
    }
    cout<<endl;
    for(i=0;i<R;i++)
    {
        for(j=0;j<C;j++)
            cout<<dp[i][j]<<" ";
        cout<<endl;
    }
}

int ok(int x,int y)
{
    if(x>=0&&x<R&&y>=0&&y<C)
        return 1;
    return 0;
}

void deal(node xx)
{
    int i,flag=0,tx,ty;
    int maximum=0;
    for(i=0;i<4;i++)
    {
        tx=xx.x+dx[i];ty=xx.y+dy[i];
        if(ok(tx,ty)&&realmap[tx][ty]<realmap[xx.x][xx.y]&&dp[tx][ty]>maximum)
        {
            maximum=dp[tx][ty];
            flag=1;
        }
    }
    if(flag)
        dp[xx.x][xx.y]=maximum+1;
    else
        dp[xx.x][xx.y]=1;
}

int main()
{
    //freopen("1088test.txt","r",stdin);
    cin>>R>>C;
    int i,j,cc=-1;
    memset(grid,0,sizeof(grid));
    memset(realmap,0,sizeof(realmap));
    memset(dp,0,sizeof(dp));
    for(i=0;i<R;i++)
    {
        for(j=0;j<C;j++)
        {
            cin>>realmap[i][j];
            grid[++cc].x=i;
            grid[cc].y=j;
            grid[cc].h=realmap[i][j];
        }
    }
    sort(grid,grid+R*C,cmp);

    for(i=0;i<R*C;i++)
    {
        deal(grid[i]);
    }
    //test();
    int ans=0;
    for(i=0;i<R;i++)
    {
        for(j=0;j<C;j++)
            if(dp[i][j]>ans)ans=dp[i][j];
    }
    cout<<ans<<endl;
    return 0;
}
侯鑫同学的代码:

侯鑫大神的代码!0ms!比我短一半!牛逼。膜拜

#include<stdio.h>
#include<string.h>
int mm[105][105],r,c;
int len[105][105],dx[4]={0,0,1,-1},dy[4]={1,-1,0,0},vis[105][105];
int dp(int i,int j)
{
    int max=0,n,m,l;
    if(vis[i][j])return len[i][j];
    else {
        for(n=0;n<4;n++){
            m=mm[i][j]-mm[i+dx[n]][j+dy[n]];//printf("%d",n);
            if(m<=0||i+dx[n]<0||i+dx[n]>=r||j+dy[n]<0||j+dy[n]>=c)continue;
            l=dp(i+dx[n],j+dy[n]);
            if(1+l>max)max=1+l;
        }
        len[i][j]=max;
        vis[i][j]=1;
        return max;
    }
}
int main()
{
    memset(vis,0,sizeof(vis));
    memset(len,0,sizeof(len));
    scanf("%d%d",&r,&c);
    int i,j,max=0;
    for(i=0;i<r;i++)
        for(j=0;j<c;j++)
        scanf("%d",&mm[i][j]);
    for(i=0;i<r;i++)
        for(j=0;j<c;j++)
        {
            len[i][j]=dp(i,j);
            if(len[i][j]>max)max=len[i][j];
        }
        printf("%d",max+1);
    return 0;
}

网上的DFS代码:

网上看到的超神器的DFS代码,非常有借鉴意义!

那个MARK数组出神入化了有木有!


#include<iostream>
#include <cstdio>
using namespace std;
int x,y;
int map[100][100];
int mark[100][100]={0};
int all=0;
int dfs(int i,int j)
{

	int k;
	if(mark[i][j]) return mark[i][j];
	if(i!=0&&map[i-1][j]<map[i][j])   {k=dfs(i-1,j)+1;if(k>mark[i][j]) mark[i][j]=k;}
	if(i!=x-1&&map[i+1][j]<map[i][j]) {k=dfs(i+1,j)+1;if(k>mark[i][j]) mark[i][j]=k;}
	if(j!=0&&map[i][j-1]<map[i][j])   {k=dfs(i,j-1)+1;if(k>mark[i][j]) mark[i][j]=k;}
	if(j!=y-1&&map[i][j+1]<map[i][j]) {k=dfs(i,j+1)+1;if(k>mark[i][j]) mark[i][j]=k;}
	return mark[i][j];

}
int main()
{
    //freopen("1088test.txt","r",stdin);
	int i,j;
	cin>>x>>y;
	for(i=0;i<x;i++)
		for(j=0;j<y;j++)
			cin>>map[i][j];

		int max=0,k;
		for(i=0;i<x;i++)
			for(j=0;j<y;j++)
			{
				k=dfs(i,j);
				if(k>max) max=k;
			}
			
			cout<<max+1<<endl;
			return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目描述 给出一个$n\times m$的矩阵,每个位置上有一个非负整数,代表这个位置的海拔高度。一开始时,有一个人站在其中一个位置上。这个人可以向上、下、左、右四个方向移动,但是只能移动到海拔高度比当前位置低或者相等的位置上。一次移动只能移动一个单位长度。定义一个位置为“山顶”,当且仅当从这个位置开始移动,可以一直走到海拔高度比它低的位置上。请问,这个矩阵中最多有多少个“山顶”? 输入格式 第一行两个整数,分别表示$n$和$m$。 接下来$n$行,每行$m$个整数,表示整个矩阵。 输出格式 输出一个整数,表示最多有多少个“山顶”。 样例输入 4 4 3 2 1 4 2 3 4 3 5 6 7 8 4 5 6 7 样例输出 5 算法1 (递归dp) $O(nm)$ 对于这道题,我们可以使用递归DP来解决,用$f(i,j)$表示以$(i,j)$为起点的路径最大长度,那么最后的答案就是所有$f(i,j)$中的最大值。 状态转移方程如下: $$ f(i,j)=\max f(x,y)+1(x,y)是(i,j)的下一个满足条件的位置 $$ 注意:这里的状态转移方程中的$x,y$是在枚举四个方向时得到的下一个位置,即: - 向上:$(i-1,j)$ - 向下:$(i+1,j)$ - 向左:$(i,j-1)$ - 向右:$(i,j+1)$ 实现过程中需要注意以下几点: - 每个点都需要搜一遍,因此需要用双重for循环来枚举每个起点; - 对于已经搜索过的点,需要用一个数组$vis$来记录,防止重复搜索; - 在进行状态转移时,需要判断移动后的点是否满足条件。 时间复杂度 状态数为$O(nm)$,每个状态转移的时间复杂度为$O(1)$,因此总时间复杂度为$O(nm)$。 参考文献 C++ 代码 算法2 (动态规划) $O(nm)$ 动态规划的思路与递归DP类似,只不过转移方程和实现方式有所不同。 状态转移方程如下: $$ f(i,j)=\max f(x,y)+1(x,y)是(i,j)的下一个满足条件的位置 $$ 注意:这里的状态转移方程中的$x,y$是在枚举四个方向时得到的下一个位置,即: - 向上:$(i-1,j)$ - 向下:$(i+1,j)$ - 向左:$(i,j-1)$ - 向右:$(i,j+1)$ 实现过程中需要注意以下几点: - 每个点都需要搜一遍,因此需要用双重for循环来枚举每个起点; - 对于已经搜索过的点,需要用一个数组$vis$来记录,防止重复搜索; - 在进行状态转移时,需要判断移动后的点是否满足条件。 时间复杂度 状态数为$O(nm)$,每个状态转移的时间复杂度为$O(1)$,因此总时间复杂度为$O(nm)$。 参考文献 C++ 代码

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值