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);
   }
}

你可能感兴趣的:(poj1088(记忆化搜索))