题意:输入长度在100内的小写字母的字符串,求把它变成回文字符串的最少交换次数.如果不能变成回文串,输入,Impossible.
解法:
要变成回文字符串,必须满足一个性质,所有的字符出现次数都是偶数,或者只有一个字符是奇数,
每次取俩端的字符,计算一下,那个花费低就选那个,注意,如果字符串长度是奇数,并且俩端某个字符应该是放在中间的位置,那么它的花费肯定是无穷大.
可以证明,如果我们s1.....e1......s2.....e2能够保证从s1-e1,e2-s2都是回文的字符串,那么放在中间的那个字符最后肯定会在中间.
#include <string> #include<iostream> #include<map> #include<memory.h> #include<vector> #include<algorithm> #include<queue> #include<vector> #include<stack> #include<math.h> #include<iomanip> #include<bitset> namespace cc { using std::cout; using std::endl; using std::cin; using std::map; using std::vector; using std::string; using std::sort; using std::priority_queue; using std::greater; using std::vector; using std::swap; using std::stack; using std::bitset; constexpr int N = 10010; string str; bool check() { int a[26] = { 0 }; int odd = 0; for (int i = 0;i < str.length();i++) { a[str[i] - 'a']++; } for (int i=0;i<26;i++) { if (a[i] % 2 == 1) { odd++; if (odd == 2) return false; } } return true; } void solve() { int n; cin >> n; while (n--) { cin >> str; if (!check()) { cout << "Impossible" << endl; continue; } int s = 0, e = str.length()-1; int total = 0; //e是最后一个元素 while (s < e) { if (str[s] == str[e]) { ++s; --e; continue; } int index1 = -1; int s1 = 0; for (int i=e;i > s; i--) { if (str[i] == str[s]) { index1 = i; break; } } if (index1 == -1) { s1 = INT32_MAX; } else s1 = e - index1; int index2 = -1; int s2 = -1; for (int i=s;i < e;i++) { if (str[i] == str[e]) { index2 = i; break; } } if (index2 == -1) { s2 = INT32_MAX; } else s2 = index2 - s; if (s2 < s1) { //select e for (int i=index2;i>s;i--) { swap(str[i],str[i-1]); ++total; } } else { //select s for (int i=index1;i<e;i++) { swap(str[i],str[i+1]); ++total; } } --e; ++s; } cout << total << endl; } } }; int main() { #ifndef ONLINE_JUDGE freopen("d://1.text", "r", stdin); #endif // !ONLINE_JUDGE cc::solve(); return 0; }