街道问题 (DP)



如图所示的矩形图中找到一条从左下角到右上角的最短路径,图中数字表示边的长度。只能向右或向上走。

【输入文件】第一行两个数,N矩形的点有NM列。(0<NM<1000)接下来N行每行M-1个数描述横向边的长度。接下来N-1行每行M个数描述纵向边的长度。边的长度小于10

【输出文件】一个数——最短路径长度。

【输入样例】

4 5

3 7 4 8

4 6 3 5

3 6 3 5

5 4 6 2

7 6 3 5 3

2 8 5 9 4

8 7 4 3 7

【输出样例】

28



        

   首先考虑穷举情况,只考虑步数,因为只能往上或右走,则要走m+n步,那么所有的情况为在(m+n)步中选择m步向右走,即 可能的方案数为 C(m+n , m),如果m和n可以达到1000的话,肯定是不行的。

   我们很快可以发现,如果在最底边,并且从一开始只往右走,那么最小的代价一定是往右走的代价和,如上图,底边1到m个点中,从左到右的代价依次为0,5,9,15,17。

同理最左边的边界从1到n的代价为0,8,10,17。那么开始考虑不是边界的情况,假设dp[i][j]代表从一开始到(i,j)的最小代价,它只能由(i-1,j)向上走或是(i,j-1)向右走得到,那么状态转移方程很容易写出:

                          dp[i][j]=min(dp[i-1][j]+up[i][j] , dp[i][j-1]+right[i][j])      ( 2<=i<=n , 2<=j<=m )

                          dp[1][i]=right[1][i]  ( 2<=i<=m  )

                          dp[i][1]=up[i][1]  (  2<=i<=n )

其中,right[][]代表向右走的代价,up[][]代表向上走的代价。dp[n][m]即为总代价。


#include<stdio.h>
int n,m,r[1003][1003],u[1003][1003],dp[1003][1003];
int Min(int a,int b)
{
    return a<b?a:b;
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        int i,j;
        for(i=n;i>=1;i--)
            for(j=2;j<=m;j++)
                scanf("%d",&r[i][j]);
        for(i=n;i>=2;i--)
            for(j=1;j<=m;j++)
                scanf("%d",&u[i][j]);

        dp[1][2]=r[1][2];               //初始化边界
        for(i=3;i<=m;i++)
            dp[1][i]=dp[1][i-1]+r[1][i];
        dp[2][1]=u[2][1];
        for(i=3;i<=n;i++)
            dp[i][1]=dp[i-1][1]+u[i][1];

        for(i=2;i<=m;i++)               //DP
            for(j=2;j<=n;j++)
                dp[j][i]=Min(dp[j-1][i]+u[j][i],dp[j][i-1]+r[j][i]);
        printf("%d\n",dp[n][m]);
    }
    return 0;
}



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值