poj1163

一道入门的很简单的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的问题,要注意边界处理,我一开始没把这个弄好,导致结果不对,还有啊,检查清楚了再上交)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值