1. 程式人生 > 其它 >試題 基礎練習 完美的代價

試題 基礎練習 完美的代價

技術標籤:藍橋杯c++

資源限制
時間限制:1.0s 記憶體限制:512.0MB


問題描述
  迴文串,是一種特殊的字串,它從左往右讀和從右往左讀是一樣的。小龍龍認為迴文串才是完美的。現在給你一個串,它不一定是迴文的,請你計算最少的交換次數使得該串變成一個完美的迴文串。
  交換的定義是:交換兩個相鄰的字元
  例如mamad
  第一次交換 ad : mamda
  第二次交換 md : madma
  第三次交換 ma : madam (迴文!完美!)


輸入格式
  第一行是一個整數N,表示接下來的字串的長度(N <= 8000)
  第二行是一個字串,長度為N.只包含小寫字母
輸出格式

  如果可能,輸出最少的交換次數。
  否則輸出Impossible


樣例輸入
5
mamad
樣例輸出
3


思路解析:

  • 首先要判斷是否滿足迴文,即沒有“物件”的字元的個數要小於等於一

我在判斷的時候使用了兩種容器:set和multiset容器。

s.begin()       //  返回指向第一個元素的迭代器
s.clear()       //  清除所有元素
s.count()       //  返回某個值元素的個數
s.empty()       //  如果集合為空,返回true(真)
s.end()         //  返回指向最後一個元素之後的迭代器,不是最後一個元素
s.equal_range
() // 返回集合中與給定值相等的上下限的兩個迭代器 s.erase() // 刪除集合中的元素 s.find() // 返回一個指向被查詢到元素的迭代器 s.get_allocator() // 返回集合的分配器 s.insert() // 在集合中插入元素 s.lower_bound() // 返回指向大於(或等於)某值的第一個元素的迭代器 s.key_comp() // 返回一個用於元素間值比較的函式 s.max_size() // 返回集合能容納的元素的最大限值 s.rbegin() // 返回指向集合中最後一個元素的反向迭代器 s.rend
() // 返回指向集合中第一個元素的反向迭代器 s.size() // 集合中元素的數目 s.swap() // 交換兩個集合變數 s.upper_bound() // 返回大於某個值元素的迭代器 s.value_comp() // 返回一個用於比較元素間的值的函式

轉載於:
(https://blog.csdn.net/love20165104027/article/details/81510406)

  • 還要滿足交換次數最少(貪心,此處不做詳解),即當遇到沒有“物件”的字元時,不需要真正的去把它交換到中間,只需要計算出該過程中需要的交換次數即可,加到count上即可。

程式碼如下:

#include<iostream>
#include<string>
#include<set>
using namespace std;
string s;//全域性變數,獲取使用者輸入的字串
bool judge(int n)
{
   multiset<char>m1;//兩種容器,set容器不能出現重複的,multiset容器可以出現重複值,
   set<char>m2;//都是定義的char型別的,不能定義成string型的,要將s中的字母以單個字元的形式存入容器。
   int flag = 0;//單個奇數字符的個數。
   for (int i = 0; i < n; i++)//利用迴圈將s中的單個字元存入容器中。
   {
   	m1.insert(s[i]);
   	m2.insert(s[i]);
   }
   multiset<char>::iterator p1 = m1.begin();
   set<char>::iterator p2 = m2.begin();
   for (p2; p2 != m2.end(); p2++)
   {
   	if (m1.count(*p2) % 2 != 0)//count的作用是返回*p2這個字元的個數。
   		flag++;//若是奇數個flag++。
   }
   if (flag > 1)//當大於一個時肯定不能構成迴文字串!
   	return false;
   else
   	return true;	
}
void show(int x)
{
   if (!judge(x))
   	cout << "Impossible" << endl;
   if(judge(x))
   {
   	int count = 0;//交換的次數。
   	int end = x-1;//字串s的末尾。
   	int i, j;
   	for (i = 0; i < end; i++)//頭開始
   	{
   		for (j = end; j > i; j--)//尾開始
   		{
   			if (s[i] == s[j])
   			{
   				for (int k = j; k <= end-1; k++)
   				{
   					swap(s[k], s[k + 1]);//將找到的對應的字元交換到尾巴。
   					count++;//次數對應增加。
   				}
   				end--;//交換完畢後,end--,就是尾巴向前一位
   				break;//此時跳出第二個迴圈,結果就是頭和尾巴都向著中間移了一位。
   			}
   		}
   		if (i == j)//此時就是代表著那個沒有“物件”的那個字元。
   		{
   			count = count + (x - 1) / 2 - i;//算出他移到中間位置的交換次數,但此時並不需要真正的進行交換,
   		}//顯然此處就是單純的是count增加了,並沒有使用swap進行交換,目的就是為了滿足最小次數。
   	}
   	cout<<count<<endl;
   }
}
int main()
{
   int n;
   cin >> n;
   cin >> s;
   show(n);
}

評測資料(可自行驗證):

  • 58
    fkgikmvqufokkuuiwqbfugwwwukigsvobbsygkokyuwgbmuqgkoqfjuiwj
  • 214

藍橋杯官網評測結果:

在這裡插入圖片描述

在這裡插入圖片描述