问题描述
回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。
交换的定义是:交换两个相邻的字符
例如mamad
第一次交换 ad : mamda
第二次交换 md : madma
第三次交换 ma : madam (回文!完美!)
输入格式
第一行是一个整数N,表示接下来的字符串的长度(N <= 8000)
第二行是一个字符串,长度为N.只包含小写字母
输出格式
如果可能,输出最少的交换次数。
否则输出Impossible
样例输入
5
mamad样例输出
3
解题思路
假如字符串所含字符个数为奇数,则有且只有一种字符的个数为奇数;为偶数则不能存在出现次数为奇数的字符。
调整交换:
从最左边到n/2枚举每个字符,从要处理的字符串的最右边开始往左找,找到相同的字符则交换到对应的位置,同时+交换次数。
如果找不到,则这个字符为处在字符串(奇数)最中间位置的字符,需要先假想不存在这个字符,当其他所有字符调整完之后再把它移到中间,+交换次数。
AC代码
#include <iostream>
using namespace std;
void Swap(char &t1,char &t2)
{
char c = t2;
t2 = t1;
t1 = c;
}
int main()
{
int n;
char ch[8005];
cin >> n >> ch;
int ans=0;
bool flag1=false,flag2=false; // flag2用于确定出现次数为奇数的字符是否为0
int r=n-1;
for(int i=0;i<=n/2;i++) {
for(int j=r;j>=i;j--) { // 从右往左找与ch[i]相同的数
if(i == j) { // 没有找到与ch[i]相同的
if(n%2 == 0 || flag2) { // 一共偶数个字符 || 已经有出现次数为奇数的字符
cout << "Impossible\n";
flag1 = true;
}
else {
flag2 = true;
ans += n/2-i; // 移到中间所需步数
}
break;
}
if(ch[i] == ch[j]) { //找到相同的
for(int k=j;k<r;k++)
Swap(ch[k],ch[k+1]); //移到对应位置
ans += (r-j);
r--; // 位置已经匹配好的不再参与之后的调整
break;
}
}
if(flag1)
break;
}
if(!flag1)
cout << ans << endl;
}
/*
9
ffdejjell
14
*/