一个比较简单的DP,希望读者在看题解之前再自己想想,争取自己AC 。
这是一个计数问题,问你从(1,1)点到(n,m)点的行走方案数,因为还有一个能量问题,一开始我为了将状态表示完整,试着开三维数组记忆化搜索,用d[i][j][k]表示当前在i,j点还有k个能量的方法数,但是总得不到正确的答案,后来我发现这么做是不正确的,为什么呢?我们要明确一点,动态规划的特点是具有很多重叠子问题,大的最优解依赖于局部最优解,且每一个状态都具有相似的意义 。 请读者注意最后一句话,这很重要 。 我们先来看题目的要求,求起点到n,m点的方案数,那么也就是说我们在n,m点一定停了,具有该点的能量,而我之前的那个表示方法却会出现很多这样的情况:在某个点却不拥有该点的能量
。简单的说,我们应该有一个具有相同意义的状态表示,用d[i][j]表示从起点到i,j点的方案数,是不是和要求的最终问题的表示方法是一样的?
明白了这点,状态转移就很好写了,对于每一个状态,枚举所有可能到达的点,将状态转移过去。
细节参见代码:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> #include<map> #include<list> #include<cmath> #include<set> #include<queue> using namespace std; typedef long long ll; const int INF = 100000000; const int mod = 10000; const long long maxn = 110; int T,n,m,d[maxn][maxn],a[maxn][maxn]; int dp(int i,int j) { if(i==n&&j==m) return 1; int& ans = d[i][j]; if(ans != -1) return ans; ans = 0; for(int k=i;k<=n;k++) { for(int l=j;l<=m;l++) { if(k==i&&l==j) continue; if(k-i+l-j <= a[i][j]) ans = (ans + dp(k,l))%mod; else break; } } return ans; } int main() { scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&a[i][j]); memset(d,-1,sizeof(d)); int ans = dp(1,1); printf("%d\n",ans); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-28 14:27:35