单向TSP

给出一个m行n列(m≤10,n≤100)的整数矩阵,从第一列任意一个位置出发,每次可以往右、右上或右下走一格,最终到达最后一列。

要求经过整数之和最小。矩阵是环形的,即最后一行向下是第一行。输出路径上每列的行号。多解时,输出字典序最小的。

下图是两个矩阵的最优路线

 

Sample Input

5 6

3 4 1 2 8 6

6 1 8 2 7 4

5 9 3 9 9 5

8 4 1 3 2 6

3 7 2 8 6 4

5 6

3 4 1 2 8 6

6 1 8 2 7 4

5 9 3 9 9 5

8 4 1 3 2 6

3 7 2 1 2 3

2 2

9 10 9 10

Sample Output

1 2 3 4 4 5

16

1 2 1 5 4 5

11

1 1

19

 

转移方程很简单,设d(i,j)为从格子(i,j)出发到最后一列的最小开销。则:

                d(i,j)=d(i,j)+min{d(i-1,j-1),d(i,j-1),d(i+1,j-1)}

主要问题在于输出路径。这就需要在计算d(i,j)时记录 " 下一列的行号 " 的最小值。

 

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long

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){
    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;
}
View Code

 

posted @ 2018-05-16 22:25  rld  阅读(206)  评论(0编辑  收藏  举报