交换次数

交换次数

IT产业人才需求节节攀升。业内巨头百度、阿里巴巴、腾讯(简称BAT)在某海滩进行招聘活动。
招聘部门一字排开。由于是自由抢占席位,三大公司的席位随机交错在一起,形如:ABABTATT,这使得应聘者十分别扭。
于是,管理部门要求招聘方进行必要的交换位置,使得每个集团的席位都挨在一起。即最后形如:BBAAATTT 这样的形状,当然,也可能是:AAABBTTT 等。
现在,假设每次只能交换2个席位,并且知道现在的席位分布,
你的任务是计算:要使每个集团的招聘席位都挨在一起需要至少进行多少次交换动作。

输入:是一行n个字符(只含有字母B、A或T),表示现在的席位分布。n<=10^4

输出:交换次数

样例输入:TABTABBTTTT

样例输出:3

来源:2018年蓝桥杯第九届决赛真题

看标签以为是一道水题结果没想到给卡住了。

思路

因为输入字符串只含有字母B、A、T,所以我们最后可以交换的结果有6种。也就是这三个字母的全排列,以样例为例如下:

AABBBTTTTTT
AATTTTTTBBB
BBBAATTTTTT
BBBTTTTTTAA
TTTTTTAABBB
TTTTTTBBBAA

接下来,我们用字符串去匹配六种结果字符串,要注意将待交换字符串分为三段,如果结果字符串是BBB、AA、TTTTTT,那么待交换字符串为TAB、TA、BBTTTT。

(注意这里不能直接一一匹配然后把不匹配的数量÷2当作交换次数,如果是只有两种字母这种做法是正确的。但是我们这里有三种,所以必须想办法如何转换。)

我们定义b、a、t为字符串内字母出现的次数。则对于样例b=3、a=2、t=6。

我们还定义Ab、At、Ba、Bt。Ab是待交换字符串的A段(即TA)出现B的数量,TA内没有B,所以Ab=0。其他同理。

TAB TA BBTTTT

B段 A段 T段

现在我们把B段里的A、T都交换到A、T段。即Ba + Bt。

交换的优先原则是B段里的A优先交换A段里的B。我们下面考虑两种交换情况下A区多出T的个数:

1.B段里的A不够用,即(Ba < Ab),B区的A都交换到A区还不能换完A区的B。所以我们需要将B区的T交换A区的B。即A区多出的T为Ab-Ba个。

2.B段里的A够用,即(Ba >= Ab),B区的A交换到A区还有剩余,剩下的A交换到T区,但这个过程B区和A区只会发生A与B的交换,B区的T不会交换到A区。即A区多出T的个数为0。为了方便编程我们记为Ab-Ab。

在B区的A、T交换完成后,A区T的个数就是 交换前A区T的个数At 和 交换后多出来T的个数Ab-min(Ba,Ab)。

所以sum = Ba + Bt + At + Ab - min(Ab,Ba)

代码里是把A段里的B、T都交换到B、T段。

代码

#include<iostream>
#include<cstring>
using namespace std;
string s;
const int INF = 0x3f3f3f3f;
int func(string s,char A,char B,char C){
 int a=0,b=0,c=0;
 int Abc=0,Ab=0,Ba=0,Bc=0,res;
 int i,j;
 for(i=0;i<s.size();i++){
  if(s[i]==A)a++;
  if(s[i]==B)b++;
  if(s[i]==C)c++;
 }
 for(i=0;i<a;i++){
  if(s[i]!=A)Abc++;
  if(s[i]==B)Ab++;
 }
 for(i=a;i<a+b;i++){
  if(s[i]==A)Ba++;
  if(s[i]==C)Bc++;
 }
 res = Abc + Bc + Ba - min(Ba,Ab);
 return res;
}
int main(){
 while(cin>>s){
  int min=INF;
  int res; 
  char c[][4]={"BAT","ATB","TBA","BTA","ABT","TAB"};
  for(int i=0;i<6;i++){
   res=func(s,c[i][0],c[i][1],c[i][2]);
   if(res<min)min=res;
  }
  cout<<min<<endl;
 }
 return 0;
}
posted @ 2021-04-10 00:02  Treasure_lee  阅读(525)  评论(0)    收藏  举报