解题思路:
使用动态规划,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分
2 人评分
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复