UVa 116 - Unidirectional TSP(单向TSP)

题目:给你一个n*m的数字表格,找到一条从左到右的路径,使得上面的数字和最小。输出字典序最小的行号路径

           (每次可以从(i,j),走到(i,j+1),(i+1,j),(i-1,j)循环无限延伸没有边界)

思路:由于要输出字典序最小的路径,所以要逆向dp,边界在n列从右到左dp

说明:逆向dp保证字典序最小(后继最小),正向能保证每点前驱最小。

//0 KB 139 ms
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define inf 0x3f3f3f3f
using namespace std;
int r,c;
int mapp[15][150];
int next[15][150];
int dp[15][150];
int main()
{
    while(~scanf("%d%d",&r,&c)){
        memset(dp,0x3f,sizeof(dp));
        memset(next,0,sizeof(next));
        for(int i=1;i<=r;i++)
        for(int j=1;j<=c;j++){
            scanf("%d",&mapp[i][j]);
        }
        int ans=inf,head;
        for(int i=1;i<=r;i++){
            dp[i][c]=mapp[i][c];
            if(c==1){  //这里wa哭我了,忘记了初始化边界时候,列数可能就是1行,所以边界就是答案,所以初始化边界时候也要确定ans的值
                if(ans>dp[i][c]){
                    ans=dp[i][c];
                    head=i;
                }
            }
        }


        for(int i=c-1;i>0;i--)
        for(int j=1;j<=r;j++){
            int row[3];
            row[0]=j;
            row[1]=(j==r? 1: j+1 );
            row[2]=(j==1? r: j-1 ) ;
            sort(row,row+3);
            dp[j][i]=inf;
            for(int k=0;k<3;k++){
                if(dp[j][i]>dp[row[k] ][i+1]+mapp[j][i] ){
                    dp[j][i]=dp[row[k] ][i+1]+mapp[j][i];
                    next[j][i]=row[k];
                }
            }

            if(i==1){
                if(ans>dp[j][i]){
                    ans=dp[j][i];
                    head=j;
                }
            }

        }

        int path=head;
        printf("%d",path);

        for(int i=1;i<c;i++){
            path=next[path][i];
            printf(" %d",path);
        }
        printf("\n%d\n",ans);

    }
    return 0;
}


你可能感兴趣的:(UVa 116 - Unidirectional TSP(单向TSP))