UVA - 116

9 篇文章 0 订阅
3 篇文章 0 订阅

UVA-116

题目大意:m行n列的矩阵,从第一列任意位置出发,可以往右上右下走一格,最终到达最后一列,求经过整数之和最小的路径,如果和相同则选择字典序小的路径

解体思路:dp,先顺推试着敲了下,因为要字典序存路径并比较字典序很复杂很复杂并且一直wrong
按小紫书上采用逆推简便很多

逆推代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define INF 0x3f3f3f3f 
using namespace std;

int m, n;
int map[100][100];
int dp[100][100];
int nx[100][100];
int main() {
    while(scanf("%d%d", &m, &n) != EOF) {
        for(int i = 0; i < m; i++)
            for(int j = 0; j < n; j++) {
                cin >> map[i][j];
            }
        int re = INF, x = 0;
        for(int j = n-1; j >= 0; j-- ) {
            for(int i = 0; i < m; i++) {
                if(j == n-1)
                    dp[i][j] = map[i][j];
                else {
                    int dis[3] = {i, i-1, i+1};
                    if(i == m-1)
                        dis[2] = 0;
                    if(i == 0)
                        dis[1] = m - 1;
                    sort(dis, dis+3);
                    dp[i][j] = INF;
                    for(int k = 0; k < 3; k++) {
                        int p = dp[dis[k]][j+1] + map[i][j];
                        if(p < dp[i][j]) {
                            dp[i][j] = p;
                            nx[i][j] = dis[k];
                        }
                    }

                    }
                if(j == 0 && dp[i][j] < re) {
                    re = dp[i][j];
                    x = i;

                }
            }
        }
        cout << x+1;
        for(int j = 0; j < n-1; j++) {
            cout << ' ' << nx[x][j]+1;
            x = nx[x][j];
        }
        cout << endl << re << endl;

    }
    return 0;
}

一开始正推的错误代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

int dis[3]= {1, 0, -1};
int s[100][101];
int dp[100][101];
int m, n;
int main() {
    while(scanf("%d%d", &m, &n) != EOF) {
        char re[100][101];
        char r[100][101];
        int l = -1;
        for(int i = 0; i < m; i++) 
            for(int j = 0; j < n; j++) {
                cin >> s[i][j];
            }
        memset(re, 0, sizeof(re));
        memset(r, 0, sizeof(r));
        memset(dp, -1, sizeof(dp));
        for(int i = 0; i < m; i++) {
            dp[i][0] = s[i][0];
            r[i][0] = i + '1';
        }
        for(int j = 1; j < n; j++) {
            for(int i = 0; i < m; i++) {
                int x, p, q;
                for(int k = 0; k < 3; k++) {
                    p = i - dis[k];
                    q = j - 1;
                    if(p >= m)
                        p = p - m;
                    else if(p < 0)
                        p = p + m;
                    x = dp[p][q] + s[i][j];
                    if(dp[i][j] == -1 || x < dp[i][j] || (x == dp[i][j] && strcmp(r[p], re[i]) < 0)) {
                        dp[i][j] = x;
                        strcpy(re[i], r[p]);
                    }
                }
                re[i][j] = i + '1';
            }
            for(int i = 0; i < m; i++) {
                strcpy(r[i], re[i]);
            }
        }
        int g = 0;
        l = dp[g][n-1];
        for(int i = 1; i < m; i++) {
            if(dp[i][n-1] < l || (dp[i][n-1] == l && strcmp(re[i], re[g]) < 0)) {
                g = i;
                l = dp[g][n-1];
            }
        }
        for(int i = 0; i < n-1; i++) {
            cout << re[g][i] << ' ';
        }
        cout << re[g][n-1] << endl << l << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值