徐若易


私信TA

用户名:dotcpp0693261

访问量:821

签 名:

等  级
排  名 35858
经  验 427
参赛次数 0
文章发表 2
年  龄 0
在职情况 学生
学  校 浙江警察学院
专  业

  自我简介:

解题思路:


使用动态规划,dp[N][L],dp[i][j]表示调整完第i位使得一样,并且进退位为v=j-L/2时(v>0表示进位,v<0表示退位,v=0表示不进退),最小的操作次数。

记两个字符串为a和b。

状态转移时,对dp[i][j]更新时,每个dp[i+1][k](k从0到L-1遍历)代表截止前一位,最小的操作数。

进退位k,先调整a[i]为a[i]+k,并且加10或减10调整至0~9数码,记录当前进位数cnt。

然后再向两个方向(加一或减一)逐步调整a[i]变成b[i],同步更新操作数和进位数,假设记为{p1,q1}和{p2,q2},这是当前最优的让a[i]变成b[i]的两种操作。

由于进位数q1和q2不等于j,那么调整进位数至j-L/2又要让操作数p1和p2倍增或倍减10的倍数。

最终取p1和p2的最小值,加上dp[i+1][k]的值。就是前一位i+1进退位k时,并可以使得当前i位进退位为j时,最小的操作次数。

k从0到L-1遍历,取上述值的最小值,就是dp[i][j]的值。


备注:感觉L=3就行了。

但是!这个思路只能拿18分!求大神指出错误!不然我真怀疑样例不对!


参考代码:


#include <bits/stdc++.h>

#define N 100010
#define L 5
 
using namespace std;

int n;
string a, b;
int dp[N][L] = {0};

pair<int, int> g(int x, int y, int mode) {
    // 返回操作数和进退位数
    int ans = 0, cnt = 0;
    while (x != y) {
        ans++;
        x += mode;
        if (x >= 10) x -= 10, cnt++;
        if (x < 0) x += 10, cnt--;
    }
    return {ans, cnt};
}

int f(int i, int j, int k) {
    int x = a[i]+k-L/2-'0', y = b[i]-'0';
    int cnt = 0; // 进位就+1,退位就-1
    if (x >= 10) x -= 10, cnt++;
    if (x < 0) x += 10, cnt--;
    auto [p1, q1] = g(x, y, 1);  // 加上去的操作数和进退位数
    auto [p2, q2] = g(x, y, -1); // 减下去的操作数和进退位数
    q1 += cnt, q2 += cnt;
    p1 += 10 * abs(q1 - j + L/2);
    p2 += 10 * abs(q2 - j + L/2);
    return min(p1, p2) + dp[i+1][k];
}

int solve(int n, string& a, string& b) {
    for (int j = 0; j < L; j++) dp[n][j] = 10 * abs(j - L/2);
    for (int i = n - 1; i >= 0; i--) {
        for (int j = 0; j < L; j++) {
            vector<int> d;
            for (int k = 0; k < L; k++) {
                d.push_back(f(i, j, k));
            }
            dp[i][j] = *min_element(d.begin(), d.end());
        }
    }
    return *min_element(dp[0], dp[0]+L);
}
 
int main() {
    while (cin >> n) {
        cin >> a >> b;
        cout << solve(n, a, b) << endl;
    }
    return 0;
}


 

0.0分

3 人评分

  评论区

我的代码在蓝桥杯官网过了, 在这里只能过一个点
2024-03-06 17:54:28
  • «
  • 1
  • »