UVA116Unidirectional TSP(DP)

来源:互联网 发布:淘宝手机自动发货 编辑:程序博客网 时间:2024/06/03 19:06

题意:给定一个n*m的矩阵,要求从第一列的任何一行出发,每次沿右或右下或右上到达后面一列,最后到第m列任何一行整个路程的最小值,并且要求是字典序最小的。


分析:最初只想到从左边往右边dp,但是需要打印最小的字典序就比较麻烦,一直解决不了。其实从右向左dp,每次从行号最小的开始转移,同时用一个数组记录到达当前点的上一个点的行号,就可以解决该问题了。


收获:

对于这种在规划最优值的同时还要求取字典序最小方案的题,选择合适的递推顺序,利用数组直接记录路径省去

循环都会是可行的选择。逆向dp保证字典序最小(后继最小),正向能保证每点前驱最小。

#include<iostream>#include<algorithm>#include<cstring>#include<cstdio>using namespace std;int mp[15][105], dp[15][105], path[15][105];int main(){    int n, m;    while(cin >> n >> m)    {        for(int i = 1; i <= n; i++)            for(int j = 1; j <= m; j++)                cin >> mp[i][j];        memset(dp, 0x3f, sizeof(dp));        for(int i = 1; i <= n; i++)            dp[i][m] = mp[i][m];        for(int i = m; i > 1; i--)            for(int j = 1; j <= n; j++)            {                int row[3] = {j-1, j, j+1};//普通情况下的行号                if(j == 1)//如果是第一行,向上的行号需要改变                    row[0] = n;                if(j == n)                    row[2] = 1;                sort(row, row+3);//先排序,再比较                for(int k = 0; k < 3; k++)                {                    int tmp = dp[j][i] + mp[row[k]][i-1];                    if(tmp < dp[row[k]][i-1])                    {                        dp[row[k]][i-1] = tmp;                        path[row[k]][i-1] = j;                    }                }            }        int cost = 0x3f3f3f3f, row;        for(int i = 1; i <= n; i++)            if(cost > dp[i][1])            {                row = i;                cost = dp[i][1];            }        printf("%d", row);        for(int i = path[row][1], j = 1; j < m; j++, i = path[i][j])            printf(" %d", i);        printf("\n%d\n", cost);    }    return 0;}


0 0
原创粉丝点击