滑雪(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;
}