原题链接:
hdu 2571 命运
本题也是属于经典的dp问题,迷宫问题。原问题应该是,迷宫每个格子里有一个数值,每次只能往右或者往下走一格,求从左上角走到右下角能获得的最大值。如果是这样,那么状态转移方程很简单,dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
但本题做了些变化,即每次我可以往右或往下移动一格,我还可以走到该行的列数是当前所在列数倍数的格子。
比如我现在在第1行第2列上,那么我下一步可以走到(2, 2)上,也可以走到(1, 3)上,还可以走到(1, 4)或(1, 6), (1, 8)上!
设dp[i][j]为起点到(i, j)这个点能得到的最大数值和
所以状态转移方程应该很好分析了。首先看(1, 1)这个点,这时它的dp值肯定就等于它自己,即dp[i][j] = a[i][j]
然后再把第一行和第一列的dp值都填充进去,最后按顺序把剩下的填充
/*
注意:向右走一格这种走法一开始写掉了,题没审仔细
*/
#include<iostream>
using namespace std;
const int MIN = -150;
int n, m;
int a[22][1005];
int dp[22][1005];
int Dp()
{
dp[1][1] = a[1][1];
//先把第一行的dp值算出来
for(int j = 2;j <= m;j++)
{
int max_dp = dp[1][j - 1]; //每次往右走一格也可以
for(int k = 1;k <= j / 2;k++)
{
if(j % k == 0)
{
if(dp[1][k] > max_dp)
max_dp = dp[1][k];
}
}
dp[1][j] = max_dp + a[1][j];
}
//再把第一列的dp值算出来,因为每次只能往下走一格
for(int i = 2;i <= n;i++)
{
dp[i][1] = dp[i - 1][1] + a[i][1];
}
//再来算一般情况
for(int i = 2;i <= n;i++)
{
for(int j = 2;j <= m;j++)
{
int max_dp = max(dp[i - 1][j], dp[i][j - 1]); //向右走一步是可以的!
for(int k = 1;k <= i / 2;k++)
{
if(j % k == 0)
{
if(dp[i][k] > max_dp)
max_dp = dp[i][k];
}
}
dp[i][j] = max_dp + a[i][j];
}
}
return dp[n][m];
}
void Clear() //Clear忘写提交肯定WA
{
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= m;j++)
{
dp[i][j] = 0;
}
}
}
int main()
{
int c;
cin >> c;
while(c-- > 0)
{
Clear();
cin >> n >> m;
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= m;j++)
{
cin >> a[i][j];
}
}
cout << Dp() << endl;
/*
可打印dp数组观察
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= m;j++)
{
cout << dp[i][j] << " ";
}
cout << endl;
}
*/
}
return 0;
}