动态规划专栏(2)多种方法解【滑雪】

                                                              滑雪(ski.pas)

{Michael喜欢滑雪。这并不奇怪,因为滑雪的确很刺激。可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你。Michael想知道在一个区域中最长的滑坡。区域由一个二维数组给出。数组的每个数字代表点的高度。下面是一个例子:

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

一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度减小。在上面的例子中,一条可行的滑坡为24-17-16-1(从24开始,在1结束)。当然25-24-23―┅―3―2―1更长。事实上,这是最长的一条。

解题思路:这道题的第一种方法:直接判断f[i][j]从哪个方向来,直接MAX(f[前后左右][前后左右]),

而第二种:要把整一个图拉成链,lis下标(首先要记录下标。),然后找到最大值。

}

STD(lis版本,Pascal)

type jl=record
  z,x,y:longint;
end;
var
  n,m,i,j,s,max,ans,k:longint;
  a:array[1..10000] of jl;//下标记录
  f:array[0..10000] of longint;//lis专用
procedure sort(l,r: longint);//排序,确保一定可以滑下去
      var
         i,j: longint;
         x,y:jl;
      begin
         i:=l;
         j:=r;
         x:=a[(l+r) div 2];
         repeat
           while a[i].z<x.z do
            inc(i);
           while x.z<a[j].z do
            dec(j);
           if not(i>j) then
             begin
                y:=a[i];
                a[i]:=a[j];
                a[j]:=y;
                inc(i);
                j:=j-1;
             end;
         until i>j;
         if l<j then
           sort(l,j);
         if i<r then
           sort(i,r);
end;
begin
  readln(n,m);
  for i:=1 to n do
    for j:=1 to m do
    begin
      inc(s);
      read(a[s].z);
      a[s].x:=i;
      a[s].y:=j;//拉直记录下标
    end;
  sort(1,n*m);
  ans:=1;
  f[n*m]:=1;
  for i:=n*m-1 downto 1 do
  begin
    k:=i;
    max:=0;
    for j:=i+1 to n*m do
     if (((a[k].x+1=a[j].x) and (a[k].y=a[j].y) and (a[k].z<>a[j].z)) or
     ((a[k].x=a[j].x) and (a[k].y+1=a[j].y) and (a[k].z<>a[j].z)) or
     ((a[k].x-1=a[j].x) and (a[k].y=a[j].y) and (a[k].z<>a[j].z)) or
     ((a[k].x=a[j].x) and (a[k].y-1=a[j].y) and (a[k].z<>a[j].z))) and (f[j]>max) then
//BFS+LIS,注意“==”特判和滑不下去
     max:=f[j];
     f[k]:=max+1;//最重要的转移方程
  end;
  max:=0;
  for i:=1 to n*m do
    if f[i]>max then
      max:=f[i];//找最大
    writeln(max);
end.
第二种 直接上!!!(c++)
#include<bits/stdc++.h>
using namespace std;
int read()//读入。。。
{
    char s;
    int k=0,base=1;
    while((s=getchar())!='-'&&s!=EOF&&!(s>='0'&&s<='9'));
    if(s==EOF)exit(0);
    if(s=='-')base=-1,s=getchar();
    while(s>='0'&&s<='9')
    {
        k=k*10+(s-'0');
        s=getchar();
    }
    return k*base;
}
void write(int x)
{
    if(x<0)
    {
        putchar('-');
        write(-x);
    }
    else
    {
        if(x/10)write(x/10);
        putchar(x%10+'0');
    }
}
int f[105][105];
int a[105][105];
int n,m,sum;
int dp(int x,int y)//再开一个函数。
{
    if (f[x][y]) return f[x][y];//直接返回值
    int sum=0;
    if (x-1>0) if (a[x-1][y]>a[x][y]) sum=max(sum,dp(x-1,y));
    if (x+1>0) if (a[x+1][y]>a[x][y]) sum=max(sum,dp(x+1,y));
    if (y-1>0) if (a[x][y-1]>a[x][y]) sum=max(sum,dp(x,y-1));
    if (y+1>0) if (a[x][y+1]>a[x][y]) sum=max(sum,dp(x,y+1));//四个转移公式,只要高于x、y,上吧!
    f[x][y]=sum+1;//找max
    return f[x][y];
}
int main()
{
    n=read();
    m=read();
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
        {
            a[i][j]=read();
        }
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
        {
            if (f[i][j]==0) f[i][j]=dp(i,j);//dp一下
            sum=max(sum,f[i][j]);//更新答案
        }
    printf("%d",sum);//输出
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值