完美的代价

问题描述
  回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。
  交换的定义是:交换两个相邻的字符
  例如mamad
  第一次交换 ad : mamda
  第二次交换 md : madma
  第三次交换 ma : madam (回文!完美!)
输入格式
  第一行是一个整数N,表示接下来的字符串的长度(N <= 8000)
  第二行是一个字符串,长度为N.只包含小写字母
输出格式
  如果可能,输出最少的交换次数。
  否则输出Impossible
样例输入
5
mamad
样例输出

3


本体的思路是:从两端开始找,从末端找到一个与开头相同的第一个字符,然后移动到回文位置即可。

注意:

1.当n为偶数时只要出现一个不成对的字母,就不是回文

2.当n为奇数时,只要出现两个不成对的就不是回文

3.当n为奇数时,最小移动次数=把不成对的移到中间的步数+将不成对的那个字符去掉剩下序列弄成回文所需要的最小步数

#include<iostream>  
  
using namespace std;  
  
char seq[8000]={0};  
int sum=0;  
  
void Swap(char &a,char&b)  //交换两个数  
{  
    char tmp;  
    tmp=a;  
    a=b;  
    b=tmp;  
}  
void Change(int sp,int np)   //把字符从sp位置移动到np位置,注意sp,np谁大谁小不一定  
{  
    if(sp==np)  
        return;  
    int tmp;  
    if(sp>np)  
        for(int i=sp;i>np;i--)  
        {  
            Swap(seq[i],seq[i-1]);  
            sum++;  
        }  
    else  
        for(int i=sp;i<np;i++)  
        {  
            Swap(seq[i],seq[i+1]);  
            sum++;  
        }  
}  
  
int main()  
{  
    int n,j,k=0,flag=1;//j用来控制尾部,k用来表示不成对的字符数,flag代表是否能构成回文序列  
    char temp;  
    cin>>n;  
    getchar();  
    gets(seq);  
    for(int i=0;i<n/2;i++)  
    {  
        j=n-i-1;  
        while(seq[i]!=seq[j]&&i<j--);//找到第一个匹配的字符的下标  
        if(i==j)//出现成单字符判断  
        {  
            if(!k&&n%2!=0)//如果k=0并且字符数为奇数  
            {  
                for(int l=i;l<n-1;l++)  
                    seq [l]=seq[l+1]; //将成单的字符去掉  
                sum+=((n-1)/2-i);//记录下将成单字符移动到中间的步数  
                n--;  
                k++;  
                i--;//由于将成单字符去掉,所以i,n都要-1  
            }  
            else  
                flag=0; //如果出现两个成单字符或字符数为偶数时出现一个成单字符flag置为0  
        }  
        else  
            Change(j,n-i-1);//如果不是成单字符,就把后面的移动到回文位置  
        if(!flag) break;//发现flag是0了立刻停止  
    }  
    if(flag)  
        cout<<sum<<endl;  
    else  
        cout<<"Impossible"<<endl;  
    return 0;  
}   



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值