题目
源地址:
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=52
理解
这道题和之前做过的一道求最大四位数和有点像。那道题我是用暴力+乱搞过得,这道题则是用了刚学的DP。 不用看题,光是看图和样例就能明白大概的题意:给定一个m*n的矩阵,要求从左往右依次选择n个数,使得这n个数的和最小。不过存在这样的限制条件:首先,每次都只能选择当前数的相邻数,也就是右上,右方,右下;其次,要求字典序最小。 找到这样的一个序列并不难,不过要求输出字典序最小的就有点麻烦。通过从右向左来扫描,就能解决这样的问题。
代码
#define MAXN 10+10
#define MAXM 100+10
int m,n;
int road[MAXN][MAXM],dp[MAXN][MAXM],path[MAXN][MAXM];
int a,b,c,Min;
int ans,id;
void init()
{
memset(road,0,sizeof(road));
memset(dp,0,sizeof(dp));
memset(path,0,sizeof(path));
for(int i=0; i<n; ++i)
{
for(int j=0; j<m; ++j)
{
scanf("%d", &road[i][j]);
}
}
}
int main(int argc, char const *argv[])
{
while(~scanf("%d%d", &n,&m))
{
init();
for(int j=m-1; j>=0; --j)
{
for(int i=0; i<n; ++i)
{
a=dp[(i-1+n)%n][j+1];
b=dp[i][j+1];
c=dp[(i+1)%n][j+1];
Min=min(a,min(b,c));
dp[i][j]=road[i][j]+Min;
path[i][j]=inf;
if(Min==a)
{
path[i][j]=(i-1+n)%n;
}
if(Min==b)
{
path[i][j]=min(path[i][j],i);
}
if(Min==c)
{
path[i][j]=min(path[i][j],(i+1)%n);
}
}
}
ans=inf;
for(int i=0; i<n; ++i)
{
if(ans>dp[i][0])
{
ans=dp[i][0],id=i;
}
}
printf("%d", id+1);
id=path[id][0];
for(int j=1; j<m; ++j)
{
printf(" %d", id+1);
id=path[id][j];
}
printf("\n%d\n",ans);
}
return 0;
}
更新日志
- 2014年11月16日 已AC。