1. 程式人生 > >藍橋杯基礎練習 完美的代價

藍橋杯基礎練習 完美的代價

iostream div amp sin 移動 第一次 第一個 對稱 個數

問題描述   回文串,是一種特殊的字符串,它從左往右讀和從右往左讀是一樣的。小龍龍認為回文串才是完美的。現在給你一個串,它不一定是回文的,請你計算最少的交換次數使得該串變成一個完美的回文串。
  交換的定義是:交換兩個相鄰的字符
  例如mamad
  第一次交換 ad : mamda
  第二次交換 md : madma
  第三次交換 ma : madam (回文!完美!) 輸入格式   第一行是一個整數N,表示接下來的字符串的長度(N <= 8000)
  第二行是一個字符串,長度為N.只包含小寫字母 輸出格式   如果可能,輸出最少的交換次數。
  否則輸出Impossible 樣例輸入 5
mamad 樣例輸出 3 解題思路: 求最少的交換次數,考慮用貪心算法,當一個字符不動,另一個字符移動到對稱位置時移動步數最少。 有字符個數為奇數和偶數兩種情況:
  1. 字符個數為偶數,不能有不對稱的字符。
  2. 字符個數為奇數,沒有對稱字符的字符只能有一個,設變量flag來標記是不是第一次不對稱。

另外需要註意:

  奇數情況下若找到不對稱字符,不能先移動它,將移動至中間所需要的步數加入總步數即可,可以想象第一個字符為非對稱字符的情況代入程序中,非對稱字符移動到中間,使得第二個字符變成第一個字符,但是外循環已經跳過了第一個字符(如果要先移動非對稱字符,則移動後需要從上一個位置重新計算)。

#include <iostream>
#include <cstdio>
using namespace std;

int main()
{
    char str[8001];
    
int n, end, j, k, cnt=0, flag=1; cin>>n;getchar(); for(int i=0; i<n; i++) scanf("%c", &str[i]); end = n-1; //end為最後一個字符下標 //從頭開始遍歷 for(int i=0; i<end; i++) { //從末尾開始遍歷 for(j=end; j>=i; j--) { //找不到相同的字符 if(i == j) {
//判斷不是第一次找不到匹配的字符 或 n為偶數 if(flag==0 || n%2==0) { //返回impossible printf("Impossible\n"); return 0; } //是第一次找不到且n為奇數,則將flag變為0,計算應該移動多少位(n/2-j)但不要真的移動 /* *不匹配的字符如果在數組的後半部分則當其他位置匹配時必然n/2==j, *即不需要移動,如果在前半部分則需要移動n/2-j,當然減i也行(此時i==j) */ else { flag = 0; cnt += n/2-i; } } //找到相同的字符 else if(str[j] == str[i]) { //將該位置的字符與向後相鄰的字符交換,直到end for(k=j; k<end; k++)//註意不能連end也算入,k+1已經替換了end { swap(str[k], str[k+1]); cnt++; } //end向前移動一位(因為該位置已經對稱) end--; break; } } } cout<<cnt<<endl; return 0; } /*註: 程序中的判斷是否找到相同字符if... else if...位置不可交換,因為i==j時, 必然str[i]==str[j],但是這是找不到的情況 */

藍橋杯基礎練習 完美的代價