codeforces 435 B. Pasha Maximizes 解题报告

题目链接:http://codeforces.com/problemset/problem/435/B

题目意思:给出一个最多为18位的数,可以通过对相邻两个数字进行交换,最多交换 k 次,问交换 k 次之后,这个数最大可以变成多少。

      不知道最近是不是疏于训练(一直研究百度之星的题目,最终决定就是暂时放下,可能能力还没达到做那种题目的水平,不过都好感谢乌冬兄耐心甘为我解答左两道题目),昨晚又想学学拓扑排序(SPFA提到),结果没看明白= =...再加上昨晚比赛...电脑卡机卡得要命,于是悲催了= =

      这个是赛后做的......做的时候不知道怎么在尽可能贪心和k次这个约束条件下取舍...看了别人的,一下子豁然开朗,晚上一打即过,哈哈哈....

      大方向就是要往贪心的策略来想。怎样贪心?当然是把位数越大的数字越往高位移动,这样保证最终得到的数尽量大,但是,有一个关键的约束条件,就是不能超过 k 次,暗含的意思就是,装载着数字比较大的位,移动到高位的距离不能超过 k 这个长度。 

      以这组数据为例:

      由于最高位的数字 9 是最大的,所以没必要讨论该位。那么从第二位数字0开始,后面的位中最大的那个数是第三位的9,将它与第二位数字交换,变成9900000078001234,次数从6变为5(因为交换了一次)....接着问题出现了,第三位的0究竟是拿最大的8(符合贪心的策略)不断与前面的数交换,还是拿次小的7不断与前面的数交换呢?如果是8,当交换5次之后,结果变成9900800007001234,而如果用7交换,结果变成9907000008001234,明显是后面的数比较大。

       所以贪心不能乱贪,前提条件就是紧紧地遵循交换次数最多不能超过当前允许的次数。

     

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <algorithm>
 6 using namespace std;
 7 
 8 const int maxn = 18 + 5;
 9 char s[maxn];
10 
11 int main()
12 {
13     int k;
14     while (cin >> s >> k)
15     {
16         int len = strlen(s);
17         for (int i = 0; i < len; i++)
18         {
19             int t = i;      // 讨论第i位的数,后面有没有更大的数可以替代它
20             for (int j = i+1; j < len && j-i <= k; j++)   // j-i <= k就是满足交换次数(实质就是j到i的距离)不能超过剩下最多能交换的次数k
21             {
22                 if (s[j] > s[t])
23                     t = j;     // 找出最大数的下标,前提是不超过k的次数
24             }
25             k -= (t-i);
26             while (t != i)   // 代表找到比要讨论的当前最高位要大的数
27             {
28                 swap(s[t], s[t-1]);   // 不断向前交换
29                 t--;
30             }
31         }
32         cout << s << endl;
33     }
34     return 0;
35 }

      

原文地址:https://www.cnblogs.com/windysai/p/3762799.html