如图所示的矩形图中找到一条从左下角到右上角的最短路径,图中数字表示边的长度。只能向右或向上走。
【输入文件】第一行两个数,N,M 矩形的点有N行M列。(0<N,M<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;
}