题目大意:给你一张第一行和最后一行连通的图,问从第一列到最后一列走过来权值和最小多少,并输出路径。图的每一个位置有一个权值。

解题思路:动态规划的题,走图所以用记忆化搜索来做:

状态: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;
}