1. 程式人生 > >(poj 1088 滑雪)

(poj 1088 滑雪)

原題戳這裡

題解

  • 一般的方法是記憶化搜尋。注意如果一個f[x][y]已經算過了,那麼直接返回就好了,相當於剪枝吧
  • 另一種方法是非遞迴的。先按高度從小到大排序,由於這樣做依然可以保證包含最長的情況,因此是正確的,而且很快。

Code

非遞迴版

// by spli
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;

const int N=110;
int n,m,cnt;
int tx[5]={0,1
,0,-1,0}; int ty[5]={0,0,1,0,-1}; int h[N][N]; struct node{ int x,y,v; }e[N*N]; int f[N][N]; int x,y,kx,ky; bool cmp(node a,node b){ return a.v<b.v; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j){ scanf("%d",&h[i][j]); e[++cnt].x=i; e[cnt].y=j; e[cnt].v=h[i][j]; } sort(e+1
,e+1+cnt,cmp); for(int i=1;i<=cnt;++i){ x=e[i].x; y=e[i].y; f[x][y]=max(f[x][y],1); for(int j=1;j<=4;++j){ kx=x+tx[j]; ky=y+ty[j]; if(kx>=1&&kx<=n&&ky>=1&&ky<=m&&h[kx][ky]>h[x][y]){ if
(f[kx][ky]<=f[x][y]+1){ f[kx][ky]=f[x][y]+1; } } } } int ans=0; for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) ans=max(ans,f[i][j]); cout<<ans; return 0; }

記憶化搜尋

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;

int n,m;
int h[110][110];
int f[110][110];
int mx[5]={0,1,0,-1,0};
int my[5]={0,0,1,0,-1};
int ans;

int dfs(int x,int y){
    if(f[x][y]) return f[x][y];
    for(int i=1;i<=4;++i){
        int nx=x+mx[i];
        int ny=y+my[i];
        if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&h[nx][ny]<h[x][y]){
            f[x][y]=max(f[x][y],dfs(nx,ny)+1);
        }
    }
    return f[x][y];
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            scanf("%d",&h[i][j]);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            dfs(i,j);       
    for(int i=1;i<=n;++i){
        for(int j=1;j<=m;++j){
            ans=max(ans,f[i][j]);
        }
    }
    cout<<ans+1<<endl;
    return 0;
}