UVA 116 - Unidirectional TSP(被这个题坑了)

虽然刘汝佳 书上写的 明明白白的 逆推 从最后一列往前推,


但是出于自己的想法比较多, 自己想的是 也可以 从前面往后推,并且自己去写, 也写出来了,结果很简单 WA。


后来想了想, 知道为什么是从第一列往最后一列推不行了。输出要求是按照字典序 输出,在从第一列开始三个方向遍历的时候


肯定按照  在保证最小值的情况下, 行数越小越好  用链表保存前一个值  在dp遍历完成之后, 扫一遍最后一列, 看看在哪一行的时候 总和最小,


然后链表往前面查询 挨个保存 在输出就好了。  在获得WA之后  想到了。 如果 最后一列 有多个小的数,那就不能确定是哪个 字典序最小了 


也想了一种方法, 把所有可能都 保存 string 里面  sort 字典序排序一下, 但是太麻烦了。 就没搞。 下面WA的代码


#include <cstdio>
#include <algorithm>
#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <set>
#include <cmath>
#include <stack>
#include <queue>
#include <cstring>
#define ll long long;
#define maxn 100
#define INF 10000000
using namespace std;
int main (){
    int ans = INF;
    int ro,co;
    while(scanf("%d%d",&ro,&co) != EOF){
        int map1[maxn][maxn] = {0};
        for(int i = 0; i < ro; i++)
            for(int j = 0; j < co; j++)
                scanf("%d",&map1[i][j]);
        int dp[maxn][maxn] = {0};
        for(int i = 0; i < ro; i++)
            dp[i][0] = map1[i][0];
        int last[maxn][maxn] = {0}; //保存路径
        for(int j = 1; j < co; j++){    //列
            for(int i = 0; i < ro; i++){ // 行
                int row[10] = {i,i-1,i+1}; //最短路径
                if(i == 0)
                    row[1] = ro-1;
                if(i == ro-1)
                    row[2] = 0;
                sort(row,row+3);
                dp[i][j] = INF;
                int flag = 0;
                for(int k = 0; k < 3; k++){
                    if(dp[row[k]][j - 1] < dp[i][j]){
                        dp[i][j] = dp[row[k]][j - 1] ;
                        if(!flag){
                            last[i][j] = row[k];
                            flag = 1;
                        }
                        else{
                            last[i][j] = row[k];
                        }
                    }
                }
                dp[i][j] += map1[i][j];

            }
        }
        int minn = 10000000;
        int x,y;
        for(int i = 0; i< ro - 1; i++){
            if(dp[i][co-1] < minn){
                minn = dp[i][co-1];
                x = i;y = co-1;
            }
        }
        vector <int> q;
        q.push_back(x+1);
        for(int i = last[x][y], j = co-1; j >= 1 ; i = last[i][j] , j--){
            q.push_back(last[i][j]+1);
        }
        int len =q.size();
        for(int i = len - 1 ; i >= 0 ; i--){
            printf("%s",i == len -1 ? "" : " ");
            printf("%d",q[i]);
        }
        printf("\n%d\n",minn);
    }
    return 0;
}

下面上AC代码


在为了字典序最小的过程中,  用了row 这个数组 然后进行排序 优先 最小的进行的那几步 很经典


#include <cstdio>
#include <algorithm>
#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <set>
#include <cmath>
#include <stack>
#include <queue>
#include <cstring>
#define ll long long;
#define maxn 100 + 10
#define INF 100000000
using namespace std;
int main (){
    int ans = INF;
    int m,n;
    while(scanf("%d%d",&m,&n) != EOF){
        int map1[maxn][maxn] = {0};
        for(int i = 0; i < m; i++)
            for(int j = 0; j < n; j++)
                scanf("%d",&map1[i][j]);
        int dp[maxn][maxn] = {0};
        int ans = INF,first = 0;
        int next[maxn][maxn];
        for(int j = n - 1; j >= 0; j--){
            for(int i = 0; i < m; i++){
                if(j == n-1) dp[i][j] = map1[i][j];
                else{
                    int row[3] = {i,i-1,i+1};
                    if(i == 0)
                        row[1] = m - 1;
                    if(i == m-1)
                        row[2] = 0;
                    sort(row,row+3);
                    dp[i][j] = INF;
                    for(int k = 0; k < 3; k++){
                        int v = dp[row[k]][j+1] + map1[i][j];
                        if(v < dp[i][j]){dp[i][j] = v;next[i][j] = row[k];}
                    }
                    if(j == 0 && dp[i][j] < ans){ans = dp[i][j];first = i;}
                }
            }
        }
        if(n == 1){
            int minn = INF;
            int x ;
            for(int i = 0 ; i < m ; i++){
                if(minn > map1[i][0]){
                    minn = map1[i][0];
                    x = i;
                }
            }
            printf("%d\n",x + 1);
            printf("%d\n",minn);
            continue;
        }
        printf("%d",first+1);
        for(int i =next[first][0],j=1; j < n; i = next[i][j],j++)
            printf(" %d",i+1);
        printf("\n%d\n",ans);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值