题意:给出一个字符串,交换相邻的字符,求最少交换次数使该字符串构成回文串。
思路:首先要判断该字符串是否可以构成回文串,先统计每个字符的出现次数,若出现次数为奇数个的字符大于一个,则无法构成回文串。然后固定左半部分,调整右边的字符,固定右半部分,调整左边的字符。这两次调整主要是看奇数个字符最中间的那个出现在哪边,若出现在右边其实只用固定左半部分,调整右侧。若出现在左边其实只用固定右半部分,调整左侧。
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <map>
using namespace std;
string s;
int solve(){
int sum = 0;
int len = s.size();
//左半部分
for(int i = 0; i < len/2; i++){
char x = s[i];
int j;
for(j = len-i-1; j > i; j--)
if(s[j] == x)
break;
if(j == len-i-1){
continue;
}
else if(j == i){//说明最中间的奇数个数的字符出现在左边。
break;
}
else if (j > i){
for(int k = j; k < len-i-1; k++){
swap(s[k],s[k+1]);
sum++;
}
}
}
//右半部分
for(int i = len-1; i >= len/2; i--) {
char x = s[i];
int j;
for(j = len-i-1; j < i; j++)
if(s[j] == x)
break;
if(j == len-i-1){
continue;
}
else if(j < i) {
for(int k = j; k > len-i-1; k--){
swap(s[k],s[k-1]);
sum++;
}
}
}
return sum;
}
int main(){
int t;
cin>>t;
while(t--){
cin>>s;
int len = s.size();
map<char,int> Map;
for(int i = 0; i < len; i++){
Map[s[i]]++;;
}
int odd_cnt = 0;
map<char,int>::iterator it;
for(it = Map.begin(); it != Map.end(); it++){
if(it->second & 1){
odd_cnt++;
}
}
if(odd_cnt < 2){
cout<<solve()<<"\n";
//cout<<s<<"\n";
}
else{
cout<<"Impossible\n";
}
}
return 0;
}