完美的代价

来源:互联网 发布:ubuntu登陆界面修改 编辑:程序博客网 时间:2024/04/30 12:01
问题描述
  回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。
  交换的定义是:交换两个相邻的字符
  例如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