使用动态规划,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 人评分
C语言程序设计教程(第三版)课后习题8.9 (Java代码)浏览:1413 |
【出圈】 (C语言代码)浏览:590 |
C语言程序设计教程(第三版)课后习题4.9 (C语言代码)浏览:1555 |
三角形 (C++代码)递归(存在大量重复计算,容易出现时间超限)浏览:836 |
A+B for Input-Output Practice (C语言代码)浏览:505 |
矩形面积交 (C++代码)浏览:1204 |
单词个数统计 (C语言代码)浏览:1046 |
淘淘的名单 (C语言代码)浏览:1309 |
C语言程序设计教程(第三版)课后习题6.10 (C语言代码)浏览:536 |
A+B for Input-Output Practice (I) (C语言代码)浏览:598 |