藍橋杯2018決賽-第九屆決賽-交換次數

題面

標題:交換次數

IT產業人才需求節節攀升。業內巨頭百度、阿里巴巴、騰訊(簡稱BAT)在某海灘進行招聘活動。
招聘部門一字排開。因爲是自由搶佔席位,三大公司的席位隨機交錯在一塊兒,形如:
ABABTATT,這使得應聘者十分別扭。
因而,管理部門要求招聘方進行必要的交換位置,使得每一個集團的席位都挨在一塊兒。即最後形如:
BBAAATTT 這樣的形狀,固然,也多是:
AAABBTTT 等。

如今,假設每次只能交換2個席位,而且知道如今的席位分佈,
你的任務是計算:要使每一個集團的招聘席位都挨在一塊兒須要至少進行多少次交換動做。

輸入是一行n個字符(只含有字母B、A或T),表示如今的席位分佈。
輸出是一個整數,表示至少交換次數。

好比,輸入:
TABTABBTTTT

程序應該輸出:
3

再好比,輸入:
TTAAABB

程序應該輸出:
0

咱們約定,輸入字符串的長度n 不大於10萬

資源約定:
峯值內存消耗(含虛擬機) < 256M
CPU消耗 < 1000ms

題解

首頁經過題目能夠知道,排序的方式有六種,分別是:ios

  • ABT
  • ATB
  • BAT
  • BTA
  • TAB
  • TBA

上面其實就是 ABT 的六種組合。咱們要作的就是將輸入的字符串,根據上面的每一種組合,每個字符交換到正確的位置上。例如輸入TABTAB,排序方式爲ABT,就須要將兩個AA交換到第 0 位和第 1 位,將兩個BB交換到第 2 位和第 3 位,最後兩個TT就是必定會在倒數第二位和第一位。由此可的,咱們只須要根據每一種組合,知道ABT的前後排序順序,依次交換直到符合條件,六組裏最少交換次數的就是最後的答案。spa

使用對拍程序生成 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;
}

知識點

  • 排列組合;
  • 交換。
相關文章
相關標籤/搜索