题目大意:给你一张第一行和最后一行连通的图,问从第一列到最后一列走过来权值和最小多少,并输出路径。图的每一个位置有一个权值。
解题思路:动态规划的题,走图所以用记忆化搜索来做:
状态:dp[i][j]-->从坐标(i,j)出发最少权值
转移方程: dp[i][j]=map[i][j]+min(dp[i-1][j+1],dp[i][j+1],dp[i+1][j+1])
由于记忆化搜索只能输出最优值。有想过这样一种思路:在dp[i][j]这个地方多加两个数来保存下一次的路径即:建一个结构体dp[i][j]。不过还是用了基本方法来写:即你找到最优路入口,然后沿着值走到最后输出出来。
AC代码如下:
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
/*
状态:dp[i][j]-->从坐标(i,j)出发最少权值
转移方程: dp[i][j]=map[i][j]+min(dp[i-1][j+1],dp[i][j+1],dp[i+1][j+1])
*/
int dp[11][110],n,m,map[11][110];
int min(int a,int b)
{
return a>b?b:a;
}
int dfs(int x,int y) //记忆化搜索最小权值路的值
{
if(x<1) x+=n;
else if(x>n) x-=n;
if(dp[x][y])
return dp[x][y];
if(y>m)
return 0;
dp[x][y]=map[x][y]+min(min(dfs(x-1,y+1),dfs(x,y+1)),dfs(x+1,y+1));
return dp[x][y];
}
int cmp(int x,int y,int z,int i) //路径寻找函数
{
int a,b,c;
if(y==1){a=y;c=x;b=z;}
else if(y==n){a=z;b=x;c=y;}
else{a=x;b=y;c=z;}
if(dp[a][i]<=dp[b][i])
{
if(dp[b][i]<=dp[c][i] || dp[a][i]<=dp[c][i])
return a;
else
return c;
}
else
{
if(dp[b][i]<=dp[c][i] )
return b;
else
return c;
}
}
int main()
{
int i,j,sum,k,t,a,b,c;
while(~scanf("%d%d",&n,&m))
{
sum=0x3f3f3f3f;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&map[i][j]);
memset(dp,0,sizeof(dp));
for(i=k=n;i>=1;i--)
{
t=dfs(i,1);
if(sum>=t)
{
sum=t;
k=i;
}
}
printf("%d",k);
for(i=2;i<=m;i++)
{
a=k-1;
b=k;
c=k+1;
if(a<1) a+=n;
if(c>n) c-=n;
k=cmp(a,b,c,i); //路径查找
printf(" %d",k);
}
printf("\n%d\n",sum);
}
return 0;
}