(1)思路:以0到9为最佳数字n,循环10次,每次循环中寻找当数字为n时达到K个数字相同时的最小代价(首先是代价,其次才是字典序);
(2)算法:从数字n开始向外扩散,采用贪心算法思想(代价为先),首先寻找相同的数字,然后寻找比该数字大1与小1的数字,然后是大2与小2的的数字,以此类推,直到到达K个相同或者到达边界;
(3)注释:代码未优化,只是基本实现了思想,如有不足欢迎指正。
#include <iostream> #include <map> #include <string> using namespace std; int main() { double N, K; string phoneNumber; while (cin >> N >> K >> phoneNumber) { //1.初始化阶段,用于定义各类数值与原始数据存储 //1.1 存储初始值 string phoneNumber_back = phoneNumber; double K_back = K; //1.2 用于存储数据,利用map的自带排序可以轻松输出最小代价的结果 map<int, string> save; //1.3 各种计数 int sameNum2CurrentNum = 0; //存储与当前num相同的数据数 int currentValue = 0; //1.4 用于存储最优解是否已经被找到 bool isBestResultFind = false; //2.大循环,实现0-9的全部查找 for (int currentNum = 0; currentNum <= 9; currentNum++) { //2.1 如果最优解已经被找到,直接跳出循环,执行第3步输出结果 if (isBestResultFind) break; //2.2 先遍历所有数值,如果相同数目已经超过了K,则将最优值赋值给save后跳出; for (int i = 0; i < N; i++) { if (phoneNumber[i] - '0' == currentNum) sameNum2CurrentNum++; } if (sameNum2CurrentNum >= K) { save.insert({ 0,phoneNumber }); isBestResultFind = true; break; } //2.3 如果2.2未满足,则根据sameNum2CurrentNum将K减小,并定义贪心算法的两个变量 int maxcurrentNum = currentNum; //currentNum向上扩张的数 int mincurrentNum = currentNum; //currentNum向下扩张的数 K = K - sameNum2CurrentNum; //2.4 贪心算法实现,currentNum同时向上下匀速扩张1,上下边界为9和0。当边界都达到,或者K被使用完后,跳出循环 while ( K || (maxcurrentNum > 9 && mincurrentNum < 0)) { if (!K) break; maxcurrentNum++; mincurrentNum--; //2.4.1 先从最大位数向最小位数查找能替换的值 if (maxcurrentNum <= 9) { for (int i = 0; i < N; i++) { if (!K) break; if (phoneNumber[i] - '0' == maxcurrentNum) { currentValue += phoneNumber[i] - '0' - currentNum; phoneNumber[i] = currentNum + '0'; K--; } } } //2.4.2 然后再从最小位数向最大位数查找能替换的值(2.4.1与2.4.2的先后顺序是为了保证字典序最小) if (mincurrentNum >= 0) { for (int i = N - 1; i >= 0; i--) { if (!K) break; if (phoneNumber[i] - '0' == mincurrentNum) { currentValue += currentNum - (phoneNumber[i] - '0'); phoneNumber[i] = currentNum + '0'; K--; } } } } //2.5 当贪心算法流程结束后,进行数据的存储,与数据的还原工作。 save.insert({ currentValue, phoneNumber }); phoneNumber = phoneNumber_back; K = K_back; sameNum2CurrentNum = 0; currentValue = 0; } //3.所有循环完成,或者最优解被查找出来后,输出结果 cout << save.begin()->first << endl; cout << save.begin()->second << endl; save.clear(); } return 0; }