题目描述
回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。
交换的定义是:交换两个相邻的字符
例如mamad
第一次交换 ad : mamda
第二次交换 md : madma
第三次交换 ma : madam (回文!完美!)
输入
第一行是一个整数N,表示接下来的字符串的长度(N < = 8000)
第二行是一个字符串,长度为N.只包含小写字母
输出
如果可能,输出最少的交换次数。
否则输出Impossible
样例输入
5 mamad
样例输出
3
分析:本题求解交换次数的基本思路是首位配对,即将左边第一个字符与右边最后一个字符开始比较,如果相符,则各向右向左移动比较下一个字符。
如果不符,则右边字符向左移动
这样求得所有交换次数加起来即为最小的
其实在每次比较并且还没有找到相符的字符时还要看一下左右两个指针是否已经相遇,如果相遇,说明字符串里面没有与该字符相配的字符,这个时候就要考虑三种情况
1、若字符串的字符数是偶数个则一定不是回文串,输出Impossible结束
2、若字符串的字符数是奇数个,则这个字符可能要放到中间不与任何字符配对。先假定这种情况进行标记,并且统计这个字符到中间位置需要交换的次数。加到总交换次数中
3、若之前已经标记过一次假定中间有字符,又遇到一次字符无法匹配的那么这种情况也无法构成回文串了,输出Impossible结束
说明:这个题还有一个细节,就是输入时不知道为什么测试数据n后面包含两个回车所以输入时还要把这两个回车给读取掉,要不然对后边输入字符串有影响。(用scanf读取,用getchar()读取回车在评测时会有部分答案错误 >_<|||)
#include<stdio.h>
const int M=8e3+5;
char str[8005];
int i,j,k,l,n,t,sum,a;
char temp;
int main(){
scanf("%d\n\n",&n);
fgets(str,M,stdin);
k=n-1;
t=0;
sum=0;
for(i=0;i<=k;i++){
for(j=k;j>=i;j--){
if(j==i){ //首尾字母相遇,说明没有找到
if(n%2==0||t==1)//如果是偶数个字符那么肯定不是回文串,还有一种情况就是
//虽然是奇数个字符,但之前已经有假设中间字符,这次又有
//无法匹配的字符,那么也肯定不是回文串
{
printf("Impossible\n");
return 0;
}
t=1;//如果是奇数个字符,那么可以暂时假设这个无法匹配的字符为中间字符
sum+=(n/2-i);//把这种假定情况需要交换的字符数量统计进去
}
else if(str[i]==str[j]){//找到相符字符
for(l=j;l<k;l++)//从找到字符位置开始到之前位置开始交换,并统计交换次数
{
temp = str[l];
str[l] = str[l+1];
str[l+1] = temp;
sum++;
}
k--;
break;
}
}
if(a==1)
break;
}
printf("%d\n",sum);
}