贪心算法:完美的代价(蓝桥杯练习题)

资源限制
时间限制:1.0s   内存限制:512.0MB

问题描述
  回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。
  交换的定义是:交换两个相邻的字符
  例如mamad
  第一次交换 ad : mamda
  第二次交换 md : madma
  第三次交换 ma : madam (回文!完美!)

输入格式
  第一行是一个整数N,表示接下来的字符串的长度(N <= 8000)
  第二行是一个字符串,长度为N.只包含小写字母
输出格式
  如果可能,输出最少的交换次数。
  否则输出Impossible

样例输入
5
mamad
样例输出
3
 
实现代码(c++)
 1 #include<iostream>
 2 using namespace std;
 3 
 4 int n=0;
 5 int num[30]={0};
 6 //思想:先检测字符是否可以形成回文数,再分单长度和偶长度进行操作,
 7 //对于一个字符串,从前到后扫描,若是次数出现为1次的,则先不动记下最后移动次数,
 8 //如果出现次数为偶数,则从该字符串的末尾去扫描,从尾部开始找到与当前字符相同的字符,再进行位置变换 
 9 int main(){
10     char s[8001];
11     int time=0; 
12     cin>>n;
13     cin>>s;
14     
15     for(int i=0;i<n;i++){
16         num[(s[i]-'a')]++;
17     } 
18     int ff=0;
19     for(int i=0;i<26;i++){
20         if(num[i]%2!=0)    ff++;
21     }
22     if(ff>=2){        //表示字符串中有2个以上的单次数出现的字符 不符合 
23         cout<<"Impossible";
24         return 0;
25     }
26     
27     if(ff==0){        //表示,没有单个次数出现的字符 不需要考虑最中间这项 
28         int t=0;    //表示已经处理好开头t个元素
29         for(int i=0;i<=n/2-1;i++){    //从头扫描到中间 
30             int flag=-1;        //标志找到最近的匹配元素的下标 
31             for(int j=n-1-t;j>i;j--){
32                 if(s[i]==s[j]){
33                     flag=j;        //保存下标 
34                     break;
35                 }
36             } 
37             
38             //进行位置的移动
39             char temp=s[flag];
40             for(int m=flag;m<n-1-t;m++){
41                 s[m]=s[m+1];
42             }
43             s[n-1-t]=temp;
44             
45             //计算元素移动的次数 
46             time+=n-1-t-flag;
47             
48             t++;    //表明字符串完成一位字符的匹配而+1 
49         } 
50     }else if(ff==1){
51         int t=0;    //表示已经处理好开头t个元素
52         for(int i=0;i<=n/2;i++){
53             int flag=-1;
54             for(int j=n-1-t;j>i;j--){
55                 if(s[i]==s[j]){
56                     flag=j;        //保存下标 
57                     break;
58                 }
59             } 
60             
61             if(flag==-1){        //表示碰见了单次数元素 
62                 //先不移动,最后移动
63                 time+=n/2-i; 
64             }else{
65                 //位置移动
66                 char temp=s[flag];
67                 for(int m=flag;m<n-1-t;m++){
68                     s[m]=s[m+1];
69                 }
70                 s[n-1-t]=temp; 
71                 
72                 //次数
73                 time+=n-1-t-flag;
74                 
75                 t++;
76             }
77         }
78     }
79     cout<<time;
80     return 0;
81 }
原文地址:https://www.cnblogs.com/xwh-blogs/p/12466671.html