从右下角左上扫描就可以了,其实不加记忆化搜索也是可以过的,记忆化搜索还不怎么会.
dp1表示左边的下一个位置,dp2表示上面的位置下一个位置
#include <iostream>
#include <cstdio>
#include <memory.h>
using namespace std;
const int maxn=1010;
int rm[maxn][maxn],dp1[maxn][maxn],dp2[maxn][maxn],n,m;
int dfs(int ci,int cj,int f){
if(f==1&&dp1[ci][cj]!=-1){
return dp1[ci][cj];
}else if(f==2&&dp2[ci][cj]!=-1){
return dp2[ci][cj];
}
int i,j;
for (j=cj-1;j>=0&&rm[ci][cj]>0;){
if(rm[ci][j]>0){
int t=dfs(ci,j,1);
rm[ci][cj]-=(j-t)+1;
j=t-1;
}else{
j--;
rm[ci][cj]--;
}
}
dp1[ci][cj]=j+1;
for (i=ci-1;i>=0;){
if(rm[i][cj]){
int t=dfs(i,cj,2);
i=t-1;
}else{
--i;
}
}
dp2[ci][cj]=i+1;
rm[ci][cj]=0;
if(f==1&&dp1[ci][cj]!=-1){
return dp1[ci][cj];
}else if(f==2&&dp2[ci][cj]!=-1){
return dp2[ci][cj];
}
}
int main(){
while (scanf("%d%d",&n,&m)==2){
for (int i=0;i<n;++i){
for (int j=0;j<m;++j){
scanf("%d",&rm[i][j]);
dp1[i][j]=-1;
dp2[i][j]=-1;
}
}
int ans=0;
for (int j=m-1;j>=0;--j){
for (int i=n-1;i>=0;--i){
if(rm[i][j]>0){
dfs(i,j,0);
ans++;
}
}
}
printf("%d\n",ans);
}
return 0;
}