题意:一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度减小。输入的第一行表示区域的行数R和列数C(1 <= R,C <= 100)。下面是R行,每行有C个整数,代表高度h,0<=h<=10000。
思路:动态规划。正向递推和递归(记忆化搜索)方式都可以。用递推时注意需要将高度排序。需要注意一个细节,如果一个位置比它四周的位置都低,那么它的高度为1,而不是0.
递推:
#include <cstdio> #include <cstring> #include <vector> #include <iostream> #include <cstdlib> #include <cmath> #include <algorithm> #define INF 0x3fffffff using namespace std; #define N 105 int dp[N][N],s[N][N]; struct point{ int x,y,h; }p[N*N]; int n,m,top = 0; int ori[4][2] = {{-1,0},{1,0},{0,1},{0,-1}}; int cmp(struct point a,struct point b){ return a.h < b.h; } int main(){ int i,j,x,y,res=0; scanf("%d %d",&n,&m); memset(dp,0,sizeof(dp)); memset(s, 0, sizeof(s)); for(i = 1;i<=n;i++) for(j = 1;j<=m;j++){ scanf("%d",&s[i][j]); p[top].x = i; p[top].y = j; p[top++].h = s[i][j]; } sort(p,p+top,cmp); for(i = 0;i<top;i++){ x = p[i].x; y = p[i].y; dp[x][y] = 1;//仔细理解题意很重要,贡献WA for(j = 0;j<4;j++) if(p[i].h > s[x+ori[j][0]][y+ori[j][1]]) dp[x][y] = max(dp[x][y],dp[x+ori[j][0]][y+ori[j][1]]+1); res = max(res,dp[x][y]); } printf("%d\n",res); return 0; }
#include <stdio.h> #include <string.h> #define M 105 int flag[M][M]; int s[M][M]; int m,n; int around[4][2] = {-1,0,0,-1,1,0,0,1}; int Max(int a,int b){ return a<b?b:a; } int dp(int x,int y){ int i,height = 0; if(flag[x][y]) return flag[x][y]; if(!x||!y||(x==n+1)||(y==m+1)) return 0; for(i = 0;i<4;i++){ int xx = x+around[i][0]; int yy = y+around[i][1]; if(s[x][y] >s[xx][yy]) height = Max(dp(xx,yy),height); } return flag[x][y] = height+1; } int main(){ int i,j,max; scanf("%d %d",&n,&m); memset(flag,0,sizeof(flag)); memset(s,0,sizeof(s)); for(i = 1;i<=n;i++) for(j = 1;j<=m;j++) scanf("%d",&s[i][j]); for(i = 1;i<=n;i++) for(j = 1;j<=n;j++) dp(i,j); for(max = 0,i = 1;i<=n;i++) for(j = 1;j<=m;j++) if(flag[i][j] > max) max = flag[i][j]; printf("%d\n",max); return 0; }
2111:题意与1088的区别:不是从高到低,而是从低到高爬坡;爬坡不是向四周,而是走“日”(象棋中的马走日);输出要求按照序列的字典序输出。
思路:仍然是dp没的说,需要考虑怎么输出。一开始怎么也转不过这个弯,认为从低到高更新,那么考虑字典序需要追溯到路径的开始才能比较。后来知道还是从高到低更新即可,这样自然保证了字典序。
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> #include <queue> using namespace std; #define INF 0x3fffffff #define clr(s,t) memset(s,t,sizeof(s)) #define N 365 int s[N][N],dp[N][N],pre[N][N],n,len; struct node{ int x,y,h; }p[N*N]; int ori[8][2] = {{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2},{-1,-2}}; int cmp(node a,node b){ return a.h > b.h; } int check(int x,int y){ return x>=1&&y>=1&&x<=n&&y<=n; } int main(){ int i,j,k,x,y; len = 0; clr(dp, 0); clr(pre, 0); scanf("%d",&n); for(i = 1;i<=n;i++) for(j = 1;j<=n;j++){ scanf("%d",&s[i][j]); p[len].x = i; p[len].y = j; p[len++].h = s[i][j]; } sort(p,p+len,cmp);//按照高度从高到低排序 for(i = 0;i<len;i++){ x = p[i].x; y = p[i].y; dp[x][y] = max(dp[x][y],1);//为了更新初始值 for(j = 0;j<8;j++){ int xx = x+ori[j][0]; int yy = y+ori[j][1]; if(check(xx, yy) && s[xx][yy]<s[x][y]){ if(dp[xx][yy] <= dp[x][y]+1){ dp[xx][yy] = dp[x][y]+1; pre[xx][yy] = j; } } } } k = dp[1][1]; x = y = 1; for(i = 1;i<=n;i++) for(j = 1;j<=n;j++) if(dp[i][j]>k ||(dp[i][j]==k&&s[i][j]<s[x][y])){ k = dp[i][j]; x = i; y = j; } printf("%d\n",k); while(k--){ printf("%d\n",s[x][y]); j = pre[x][y]; x -= ori[j][0]; y -= ori[j][1]; } return 0; }