poj1088(记忆化搜索)

题意:在一个二维的数组里面,搜索出一条按降序排列的最长子序列,输出长度,如果像我之前对于每个点都进行都搜索一次,明显就会重复经过很多点,然后TLE。所以既可以采用记忆化搜索,用一个数组保存已经搜过的点,也可以用动态规划推递推方程。
记忆化搜索,搜索递归的退出条件是达到最长的的降序子序列的长度,并返回保存在数组里,实现记载,下次遇到该点就不用再搜一次!

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int dp[110][110],M[110][110],next[4][2]={{-1,0},{0,1},{1,0},{0,-1}},n,m;
int dfs(int x,int y)
{
   if(dp[x][y])
     return dp[x][y];
   int sum=1;
   for(int i=0;i<4;i++)
   {
       int tx=x+next[i][0];
       int ty=y+next[i][1];
       if(tx<0||ty<0||tx>=n||ty>=m||M[tx][ty]>=M[x][y])
         continue;
       sum=max(sum,dfs(tx,ty)+1);
   }
   return dp[x][y]=sum;
}

int main()
{
    while(~scanf("%d %d",&n,&m))
    {
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
            scanf("%d",&M[i][j]);
        memset(dp,0,sizeof(dp));
        int maxx=-1;
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
            maxx=max(maxx,dfs(i,j));
        printf("%d\n",maxx);
    }
}

**虽然,这题我跟倾向于记忆化搜索(代码少),最近刚入门dp,刚好看到有这题的分类,再奉上dp推出递推方程式的写法。
有两种dp的写法,一种 “我为人人”,的思想就是用自己去更新周围相关的状态,比如这题如果周围遇到比自己大的点,就尝试去更新周围点加+1,注意这题更新的方向是从小到大。
将所有点按高度从小到大排序。(规定搜索的方向,从最小的点更新比他大的点的状态,必须要) 每个点的 L 值都初始化为 1
从小到大遍历所有的点。经过一个点(i,j)时,要更新他周围的,比它高的点
的L值。例如:**
**if H(i+1,j) > H(i,j) // H代表高度
dp(i+1,j) = max(dp(i+1,j),dp(i,j)+1)**

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct Node
{
    int x,y,h;
}node[10010];
int Next[4][2]={{-1,0},{0,1},{1,0},{0,-1}},height[110][110],dp[110][110];
bool cmp(Node a,Node b)
{
    return a.h<b.h;
}

int main()
{
   int n,m;
   #ifdef yexiaoju
     freopen("Untitled2.txt","r",stdin);
   #endif // yexiaoju
   while(~scanf("%d %d",&n,&m))
   {
       int num=0;
       for(int i=1;i<=n;i++)
       {
         for(int j=1;j<=m;j++)
         {
             scanf("%d",&height[i][j]);
             node[num].x=i,node[num].y=j,node[num++].h=height[i][j];
             dp[i][j]=1;
         }
       }
       sort(node,node+num,cmp);
       for(int i=0;i<n*m;i++)
       {
           for(int j=0;j<4;j++)
           {
               int tx=node[i].x+Next[j][0];
               int ty=node[i].y+Next[j][1];
               if(tx>0&&ty>0&&tx<=n&&ty<=m&&height[tx][ty]>node[i].h)
               {
                  dp[tx][ty]=max(dp[tx][ty],dp[node[i].x][node[i].y]+1);
               }
           }
       }
       int Max=-1;
       for(int i=1;i<=n;i++)
         for(int j=1;j<=m;j++)
         if(dp[i][j]>Max)
            Max=dp[i][j];
         printf("%d\n",Max);
   }
}

还有一种 人人为我,思想 用别人的状态来更新自己的状态,比如这题,每一个点搜索遇到周围有比他小的,就判断一下
dp[x][y]=max(dp[x][y],dp[nextx][nexty]+1);

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct Node
{
    int x,y,h;
}node[10010];
int Next[4][2]={{-1,0},{0,1},{1,0},{0,-1}},height[110][110],dp[110][110];
bool cmp(Node a,Node b)
{
    return a.h<b.h;
}

int main()
{
   int n,m;
   #ifdef yexiaoju
     freopen("Untitled2.txt","r",stdin);
   #endif // yexiaoju
   while(~scanf("%d %d",&n,&m))
   {
       int num=0;
       for(int i=1;i<=n;i++)
       {
         for(int j=1;j<=m;j++)
         {
             scanf("%d",&height[i][j]);
             node[num].x=i,node[num].y=j,node[num++].h=height[i][j];
             dp[i][j]=1;
         }
       }
       sort(node,node+num,cmp);
       for(int i=0;i<n*m;i++)
       {
           for(int j=0;j<4;j++)
           {
               int tx=node[i].x+Next[j][0];
               int ty=node[i].y+Next[j][1];
               if(tx>0&&ty>0&&tx<=n&&ty<=m&&height[tx][ty]<node[i].h)
               {
                  dp[node[i].x][node[i].y]=max(dp[node[i].x][node[i].y],dp[tx][ty]+1);
               }
           }
       }
       int Max=-1;
       for(int i=1;i<=n;i++)
         for(int j=1;j<=m;j++)
         if(dp[i][j]>Max)
            Max=dp[i][j];
         printf("%d\n",Max);
   }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值