解题思路:
使用动态规划,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、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复