您的位置:首页 > 其它

蓝桥杯---完美的代价

2018-02-06 12:34 411 查看
问题描述
  回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。

  交换的定义是:交换两个相邻的字符

  例如mamad

  第一次交换 ad : mamda

  第二次交换 md : madma

  第三次交换 ma : madam (回文!完美!)
输入格式
  第一行是一个整数N,表示接下来的字符串的长度(N <= 8000)

  第二行是一个字符串,长度为N.只包含小写字母
输出格式
  如果可能,输出最少的交换次数。

  否则输出Impossible
样例输入
5

mamad
样例输出
3

解决办法:

一、输出Impossible

不必考虑是字符串长度为奇数偶数

只需考虑,出现次数为奇数的字母个数,若个数 等于或大于2 ,则不能构成回文

当所有字母次数都为偶数时,一定可以构成回文

如:

abbchca

h出现次数为1,且只有h出现次数为奇数,能构成回文

abbbchca

b出现次数为3,h为1,则有两个奇数字母,不能构成回文

abbchhca

所有字母出现次数都为偶数,必定可以构成回文

二、能构成回文

1、注意

交换的定义是:交换两个相邻的字母

2、要保证交换次数最少,则每个字母都是单向移动。

3、从外部开始向内,因为内部的改变不影响外部已排好的序列,不会产生重复。

4、找到中点(l+1)/2 (l为字符串长度,l从1开始):i<(l+1)/2,i从0开始,这个可以自己试一下

从左边第一个作为定点(不移动位置)开始,查找自右第一个往左找到相同字母,将相同字母移动到回文对应位置,记录交换次数

从左边第二个作为定点开始,查找自右第二个往左找到相同字母,将相同的字母移动到对应的位置,记录交换次数

以此类推。

注意:在这个过程中不改变外部排好的序列,外部已排好的下次查找可直接略过。(见3)

如图:最少交换次数为3



5、如果存在字母在未排序内找不到相同字母(即单个的奇数字母),或者单个的字母出现在字符串中点左边(在右边时会因为各个字母的交换而最后被换到中点位置去)

//比如h出现3次,则在字符串中最靠左与最靠右(交换次数最少)的h可配成一对回文,剩下一个放中点位置

先不移动,计算该字母到中点所需交换次数,然后将它忽略,继续从它下个字母进行回文排列

注意:

此时对应位置发生改变

//比如一个长度为7的字符串,若左边第一个字母即为单个的奇数字母,那么左边第二个字母对应的回文的位置为右边第一个

当后面字符串形成回文时,再移动该奇数字母至中点位置

//若先移动,则每个字母排序时交换的次数+1

如图:最少交换次数为6





#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int l;
scanf("%d",&l);
char a[l];
//清除一个无效字符---回车
getchar();
//输入字符串a
gets(a);
//数组b的26个变量分别对应26个字母
int b[26]={0},i;
//统计字符串中各字母出现的次数
for(i=0;i<l;i++)
{
b[a[i]-'a']++;
}
//统计出现次数为奇数的字母个数
int k=0;
for(i=0;i<26;i++)
{
if(b[i]%2!=0)
k++;
}
//若存在2个及以上次数为奇数的字母
if(k>=2)
{
printf("Impossible");
exit(0);
}
else
{
//h计形成回文所需次数,
//m计奇数字符串时,奇数字母到达中点位置所需次数
//g用于改变交换位置长度
int h=0,g=l,m=0;
for(i=0;i<(l+1)/2;i++)
{
int j;
//查找是否存在不同位置的相同字母
for(j=g-1;j>i;j--)
{
//存在
if(a[i]==a[j])
{
while(j<g-1)
{
//交换至对应位置
char t;
t=a[j];
a[j]=a[j+1];
a[j+1]=t;
j++;
h++;//记录次数
}
g--;
break;
}
}
//不存在,则为奇数字母
if(j==i)
m=(l-1)/2-i;
}
printf("%d",h+m);
}
return 0;
}代码应该是存在...不足的呃,但是大概思路是这样子
如有误,或者是说不清楚的地方,欢迎大家告诉我~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息