题目描述:
链接:https://www.nowcoder.com/questionTerminal/005af31a10834b3688911463065ab47d
来源:牛客网
A 国的手机号码由且仅由 N 位十进制数字(0-9)组成。一个手机号码中有至少 K 位数字相同则被定义为靓号。A 国的手机号可以有前导零,比如 000123456 是一个合法的手机号。 小多想花钱将自己的手机号码修改为一个靓号。修改号码中的一个数字需要花费的金额为新数字与旧数字之间的差值。比如将 1 修改为 6 或 6 修改为 1 都需要花 5 块钱。 给出小多现在的手机号码,问将其修改成一个靓号,最少需要多少钱?
输入描述:
第一行包含2个整数 N、K,分别表示手机号码数字个数以及靓号至少有 K 个数字相同。
第二行包含 N 个字符,每个字符都是一个数字('0'-'9'),数字之间没有任何其他空白符。表示小多的手机号码。
数据范围:
2 <= K <= N <= 10000
输出描述:
第一行包含一个整数,表示修改成一个靓号,最少需要的金额。
第二行包含 N 个数字字符,表示最少花费修改的新手机号。若有多个靓号花费都最少,则输出字典序最小的靓号。
思路分析:
是一道贪心求解的题。由于一共就10个数字,求每一位数字作为靓号的花费。例如对于787585这个号,n=6,k=5。首先判断设置5个9的情况,再针对设置每个数字到9的花费进行排序。这里利用了一个结构体,包含了当前数的在号码的位置,其初始值,其目标值,以及从初始值转换到目标值所需要的花费。将花费从小到大进行排序,对于花费一致的数,这里需要输出字典序最小的结果,因此当当前数比目标数小,优先处理后面的数。
代码:
1 #include<stdio.h> 2 #include<iostream> 3 #include<vector> 4 #include<algorithm> 5 #include<stdlib.h> 6 #include<limits.h> 7 using namespace std; 8 9 struct node{ 10 int cosume; 11 int idx; 12 int target; 13 int ori; 14 }; 15 16 int cmp(node a, node b) 17 { 18 if(a.cosume!=b.cosume) 19 return a.cosume < b.cosume; 20 if(a.idx < b.idx) 21 return a.target < a.ori; 22 return b.target > b.ori; 23 } 24 25 void process(int num[], int n, int k) 26 { 27 int cnt = INT_MAX, tmp; 28 int i,j; 29 node nx[n]; 30 int res[n]; 31 for(i=9; i>=0; i--) 32 { 33 for(j=0; j<n; j++) 34 { 35 nx[j].cosume = abs(i-num[j]); 36 nx[j].idx = j; 37 nx[j].target = i; 38 nx[j].ori = num[j]; 39 } 40 sort(nx, nx+n, cmp); 41 tmp = 0; 42 for(j=0; j<k; j++) 43 tmp += nx[j].cosume; 44 if(tmp <= cnt) 45 { 46 cnt = tmp; 47 for(j=0; j<n; j++) 48 res[j] = num[j]; 49 for(j=0; j<k; j++) 50 res[nx[j].idx] = i; 51 } 52 } 53 printf("%d\n", cnt); 54 for(i=0; i<n; i++) 55 printf("%d", res[i]); 56 printf("\n"); 57 } 58 59 int main() 60 { 61 int n,k; 62 scanf("%d%d", &n, &k); 63 char number[n]; 64 scanf("%s", number); 65 int num[n]; 66 for(int i=0; i<n; i++) 67 num[i] = number[i]-'0'; 68 process(num, n, k); 69 return 0; 70 }