问题:
给你一个n行m列的整数矩形,从第一列任何一个位置出发每次往右,右上或右下走一格,最终到达最后一列。要求经过的整数之和最小,整个矩形是环形的,即第一行的上一行是最后一行,最后一行的下一行是第一行,输出路径上每列的行号,多解时输出字典序最小的。
分析:
每一列就是一个状态,这个状态是由前一列的右上,右,右下得到的,要得到每个状态的最小值,只需比较右上,右,右下的最小值就好了。就得得到了下面的状态转移方程:
dp[i][j]=dp[i][j]+min(dp[i-1][j-1],dp[i][j-1],dp[i+1][j-1]);
在输出最小字典序的时候,可以采用之前用过的方法。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxx=10000;
int G[maxx][maxx];
int dp[maxx][maxx];
int n,m,ar[3];
int compare_min(int a,int b,int c) //比较a,b,c中最小的一个
{
ar[0]=a,ar[1]=b,ar[2]=c;
sort(ar,ar+3);
return ar[0];
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>G[i][j];
for(int j=0,i=1;i<=n;i++)
dp[i][j]=0;
for(int j=1;j<=m;j++)
for(int i=1;i<=n;i++)
{
if(i==1)
dp[i][j]=G[i][j]+compare_min(dp[n][j-1],dp[i][j-1],dp[i+1][j-1]);
else if(i==n)
dp[i][j]=G[i][j]+compare_min(dp[i-1][j-1],dp[i][j-1],dp[1][j-1]);
else
dp[i][j]=G[i][j]+compare_min(dp[i-1][j-1],dp[i][j-1],dp[i+1][j-1]);
}
int ans=(1<<30);
for(int j=m,i=1;i<=n;i++)
if(ans>dp[i][j])
ans=dp[i][j];
cout<<ans<<endl;
int road[m],cns=0;
for(int j=m;j>=1;j--)
{
for(int i=1;i<=n;i++)
{
if(dp[i][j]==ans)
{
road[cns]=i;
break;
}
}
ans=ans-G[road[cns]][j];
cns++;
}
for(int i=m-1;i>=0;i--)
cout<<road[i]<<" ";;
cout<<endl;
return 0;
}
感觉这个问题很简单,是自己独立想出来的,也是独立的写完了自己的代码,继续努力。书上的方法好像不一样我再研究一下。