题面
标题:交换次数
IT产业人才需求节节攀升。业内巨头百度、阿里巴巴、腾讯(简称BAT)在某海滩进行招聘活动。
招聘部门一字排开。由于是自由抢占席位,三大公司的席位随机交错在一起,形如:
ABABTATT,这使得应聘者十分别扭。
于是,管理部门要求招聘方进行必要的交换位置,使得每个集团的席位都挨在一起。即最后形如:
BBAAATTT 这样的形状,当然,也可能是:
AAABBTTT 等。
现在,假设每次只能交换2个席位,并且知道现在的席位分布,
你的任务是计算:要使每个集团的招聘席位都挨在一起需要至少进行多少次交换动作。
输入是一行n个字符(只含有字母B、A或T),表示现在的席位分布。
输出是一个整数,表示至少交换次数。
比如,输入:
TABTABBTTTT
程序应该输出:
3
再比如,输入:
TTAAABB
程序应该输出:
0
我们约定,输入字符串的长度n 不大于10万
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms
题解
首页通过题目可以知道,排序的方式有六种,分别是:
- ABT
- ATB
- BAT
- BTA
- TAB
- TBA
上面其实就是 ABT 的六种组合。我们要做的就是将输入的字符串,根据上面的每一种组合,每一个字符交换到正确的位置上。例如输入TABTAB
,排序方式为ABT
,就需要将两个AA
交换到第 0 位和第 1 位,将两个BB
交换到第 2 位和第 3 位,最后两个TT
就是一定会在倒数第二位和第一位。由此可的,我们只需要根据每一种组合,知道ABT
的先后排序顺序,依次交换直到符合条件,六组里最少交换次数的就是最后的答案。
使用对拍程序生成 10 万的数据,能够在本机 1 秒内执行。
代码
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <vector>
#include <map>
#include <fstream>
using namespace std;
string s;
map<char, int> M;
// ABT 出现的组合情况
char per[6][3] = {
{'A', 'B', 'T'},
{'A', 'T', 'B'},
{'B', 'A', 'T'},
{'B', 'T', 'A'},
{'T', 'A', 'B'},
{'T', 'B', 'A'},
};
int minimumSwapCount (char com[]) {
map<char, int> m1, m2, m3;
char c1 = com[0], c2 = com[1], c3 = com[2];
int l = 0;
int r = M[c1];
int res = 0;
for (int i = l; i < r; i++)
m1[s[i]]++;
l = r;
r = l + M[c2];
for (int i = l; i < r; i++)
m2[s[i]]++;
l = r;
r = s.length();
for (int i = l; i < r; i++)
m3[s[i]]++;
// printf("A = %d, B = %d, T = %d\n", m1['A'], m1['B'], m1['T']);
// printf("A = %d, B = %d, T = %d\n", m2['A'], m2['B'], m2['T']);
// printf("A = %d, B = %d, T = %d\n", m3['A'], m3['B'], m3['T']);
// cout << endl;
// m1 只能有 c1 存在,c2 和 c3 都需要与 m2, m3 交换
while (m1[c2]) {
if (m2[c1]) {
m1[c1]++;
m2[c1]--;
m1[c2]--;
m2[c2]++;
res++;
} else if (m3[c1]) {
m1[c1]++;
m3[c1]--;
m1[c2]--;
m3[c2]++;
res++;
}
}
while (m1[c3]) {
if (m2[c1]) {
m1[c1]++;
m2[c1]--;
m1[c3]--;
m2[c3]++;
res++;
} else if (m3[c1]) {
m1[c1]++;
m3[c1]--;
m1[c3]--;
m3[c3]++;
res++;
}
}
// m1 经过与 m2 和 m3 的交换后,m1 里只会保留 c1
// m2 里可能还有 c2 和 c3 的值,与 m3 交换
while (m2[c3]) {
if (m3[c2]) {
m2[c2]++;
m3[c2]--;
m2[c3]--;
m3[c3]++;
res++;
}
}
// 经过上面的循环,m1 内只有 c1,m2 内只有 c2,由此 m3 内只会有 c3
// 返回本次组合的交换次数
return res;
}
int main () {
cin >> s;
// ifstream infile;
// infile.open("in.txt");
// infile >> s;
int n = s.length(), ans = 1 << 21;
// 求出输入字符串中,A、B 和 T 的出现次数
for (int i = 0; i < n; i++)
M[s[i]]++;
// 求每种组合最小的交换次数
for (int i = 0; i < 6; i++)
ans = min(ans, minimumSwapCount(per[i]));
cout << ans << endl;
return 0;
}
知识点
- 排列组合;
- 交换。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。