Description
设有一个n×m(小于100)的方格(如图所示),在方格中去掉某些点,方格中的数字代表距离(为小于100的数,如果为0表示去掉的点),试找出一条从A(左上角)到B(右下角)的路径,经过的距离和为最小(此时称为最小代价),从A出发的方向只能向右,或者向下。
Sample Input
4 4
4 10 7 0
3 2 2 9
0 7 0 4
11 6 12 1
Sample Output
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(3,4)->(4,4)
24
思路
有2种方法:顺推,逆推
顺推:
设b[i][j]为从1,1到i,j的最小代价(走不了为0)
若
b
[
i
]
[
j
−
1
]
!
=
0
则
b
[
i
]
[
j
]
=
m
i
n
(
b
[
i
]
[
j
−
1
]
,
b
[
i
]
[
j
]
)
若b[i][j-1]!=0则 b[i][j]=min(b[i][j-1],b[i][j])
若b[i][j−1]!=0则b[i][j]=min(b[i][j−1],b[i][j])
若
b
[
i
−
1
]
[
j
]
!
=
0
则
b
[
i
]
[
j
]
=
m
i
n
(
b
[
i
−
1
]
[
j
]
,
b
[
i
]
[
j
]
)
若b[i-1][j]!=0则 b[i][j]=min(b[i-1][j],b[i][j])
若b[i−1][j]!=0则b[i][j]=min(b[i−1][j],b[i][j])
最后要加上这条路的代价
注意来时的路是要同时记录的
(
1
<
=
i
<
=
n
,
1
<
=
j
<
=
m
)
(1<=i<=n,1<=j<=m)
(1<=i<=n,1<=j<=m)
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<map>
#include<string>
using namespace std;
int a[109][109],n,m,b[109][109],c[109][109];
int main()
{
cin>>n>>m;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++) cin>>a[i][j];
}
int o=0;
for (int i=1;i<=n;i++)
{
if (a[i][1]==0) o=1;
if (o==1) a[i][1]=0;
c[i][1]=1,b[i][1]=(a[i][1]==0?0:b[i-1][1]+a[i][1]);
}
o=0;
for (int j=1;j<=m;j++)
{
if (a[1][j]==0) o=1;
if (o==1) a[1][j]=0;
c[1][j]=2,b[1][j]=(a[1][j]==0?0:b[1][j-1]+a[1][j]);
}
for (int i=2;i<=n;i++)
{
for (int j=2;j<=m;j++)
{
if (a[i][j]==0) continue;
if (a[i][j-1]==0&&a[i-1][j]==0) continue;
if (a[i][j-1]==0)
{
b[i][j]=b[i-1][j]+a[i][j];
c[i][j]=1;
continue;
}
if (a[i-1][j]==0)
{
b[i][j]=b[i][j-1]+a[i][j];
c[i][j]=2;
continue;
}
if (b[i-1][j]>b[i][j-1])
{
b[i][j]=b[i][j-1]+a[i][j];
c[i][j]=2;
}
else
{
b[i][j]=b[i-1][j]+a[i][j];
c[i][j]=1;
}
}
}
int dx[10001],dy[10001],dxy=0;
int x=n,y=m;
while (x>1||y>1)
{
dx[dxy]=x;
dy[dxy++]=y;
if (c[x][y]==1) x--;
else y--;
}
cout<<"(1,1)";
for (int i=dxy-1;i>=0;i--) cout<<"->("<<dx[i]<<','<<dy[i]<<')';//注意路径的输出格式
cout<<endl<<b[n][m]-a[n][m];
return 0;
}
逆推:
设b[i][j]为从n,m到i,j的最小代价
若
b
[
i
]
[
j
+
1
]
!
=
0
,
b
[
i
]
[
j
]
=
m
i
n
(
b
[
i
]
[
j
]
,
b
[
i
]
[
j
+
1
]
)
若b[i][j+1]!=0,b[i][j]=min(b[i][j],b[i][j+1])
若b[i][j+1]!=0,b[i][j]=min(b[i][j],b[i][j+1])
若
b
[
i
+
1
]
[
j
]
!
=
0
,
b
[
i
]
[
j
]
=
m
i
n
(
b
[
i
]
[
j
]
,
b
[
i
+
1
]
[
j
]
)
若b[i+1][j]!=0,b[i][j]=min(b[i][j],b[i+1][j])
若b[i+1][j]!=0,b[i][j]=min(b[i][j],b[i+1][j])
依然要加上这条路的代价,依然是记录来时的路,依然是
(
1
<
=
i
<
=
n
,
i
<
=
j
<
=
m
)
(1<=i<=n,i<=j<=m)
(1<=i<=n,i<=j<=m)
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<map>
#include<string>
using namespace std;
int a[109][109],n,m,b[109][109],c[109][109];
int main()
{
cin>>n>>m;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++) cin>>a[i][j];
}
int o=0;
for (int i=n;i>=1;i--)
{
if (a[i][m]==0) o=1;
if (o==1) a[i][m]=0;
c[i][m]=1,b[i][m]=(a[i][m]==0?0:b[i+1][m]+a[i][m]);
}
o=0;
for (int j=m;j>=1;j--)
{
if (a[n][j]==0) o=1;
if (o==1) a[n][j]=0;
c[n][j]=2,b[n][j]=(a[n][j]==0?0:b[n][j+1]+a[n][j]);
}
for (int i=n-1;i>=1;i--)
{
for (int j=m-1;j>=1;j--)
{
if (a[i][j]==0) continue;
if (a[i+1][j]==0&&a[i][j+1]==0) continue;
if (a[i+1][j]==0)
{
b[i][j]=b[i][j+1]+a[i][j];
c[i][j]=2;
continue;
}
if (a[i][j+1]==0)
{
b[i][j]=b[i+1][j]+a[i][j];
c[i][j]=1;
continue;
}
if (b[i][j+1]>b[i+1][j])
{
b[i][j]=b[i+1][j]+a[i][j];
c[i][j]=1;
}
else
{
b[i][j]=b[i][j+1]+a[i][j];
c[i][j]=2;
}
}
}
/* for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++) cout<<b[i][j]<<' ';
cout<<endl;
}一定要注意检查dp数组
*/ int dx[10001],dy[10001],dxy=0;
int x=1,y=1;
while (x<=n&&y<=m)
{
dx[dxy]=x;
dy[dxy++]=y;
if (c[x][y]==1) x++;
else y++;
}
cout<<"(1,1)";
for (int i=1;i<dxy;i++) cout<<"->("<<dx[i]<<','<<dy[i]<<')';
cout<<endl<<b[1][1]-a[n][m];
return 0;
}