一道入门的很简单的dp题目,(最近刚学dp,看不懂dp的原理,今天再来看着道题目,突然就有些明白了)
对动态规划的理解,就是站在全局角度找最优解,那么你要先去找比它前一步的最优解,前一步如果不满足最优解的话,那么就没办法满足全局最优解了,这一点就叫做最优子结构。dp与贪心不同的是,贪心只满足下一步的局部最优解,而不是全局。所以动规对于问题的思考方式其实就是把一个大问题细分为一个一个小问题,把这个问题的步骤细化,往前推理,我们要利用dp做题,就要找到合适的子问题,找到每一步递推的关系式。下面以poj1163为例看一下dp的写法。
1.利用递归(我目前只会简单的c语言.....所以代码水平还比较低,.....)
#include<stdio.h>
#define INF 100
void read(int a[][INF],int m)
{
int i,j;
for(i=0;i<m;i++)
{
for(j=0;j<=i;j++)
scanf("%d",&a[i][j]);
}
}
int dp(int i,int j,int a[][INF],int m)
{
if (i==m-1)
return a[i][j];
else return a[i][j]+(dp(i+1,j,a,m)>dp(i+1,j+1,a,m)?dp(i+1,j,a,m):dp(i+1,j+1,a,m));
}
int main()
{
int a[INF][INF],m;
while (scanf("%d",&m)!=EOF)
{
read(a,m);
int c=dp(0,0,a,m);
printf("%d\n",c);
}
return 0;
}
如果这样写的话,提交上去发现会被T,为什么呢?这个时候我们需要再返回来看下我们这个代码运行的过程(如果程序被T,我们可以思考一下是不是有哪些地方不必要计算的?有没有重复计算的?)
我们可以从上往下思考,会发现有一些节点被重复计算了。那么我们能不能换一种写法,避免这些节点被重复计算呢?
关系式还是那个关系式子,但是我们的问题在于从上往下写会重复计算,那么如果试试从下往上写呢?那么这个时候不满足写递归的条件,我们可以试试用递推来写
#include<stdio.h>
#define INF 100
void read(int a[][INF],int m)
{
int i,j;
for(i=0;i<m;i++)
{
for(j=0;j<=i;j++)
scanf("%d",&a[i][j]);
}
}
int dp(int a[][INF],int m)
{
int i,j;
for(i=m-2;i>=0;i--)
{
for(j=0;j<=i;j++)
{
if(a[i+1][j+1]>a[i+1][j])
a[i][j]+=a[i+1][j+1];
else a[i][j]+=a[i+1][j];
}
}
return a[0][0];
}
int main()
{
int a[INF][INF],m;
while (scanf("%d",&m)!=EOF)
{
read(a,m);
int c=dp(a,m);
printf("%d\n",c);
}
return 0;
}
(关于数组里面,下标的问题,尤其涉及到比较时候有+1,-1的问题,要注意边界处理,我一开始没把这个弄好,导致结果不对,还有啊,检查清楚了再上交)