计蒜君,上线
这题其实也不难,只要【贪心策略】就可以了。
回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。
交换的定义是:交换两个相邻的字符
例如mamad
第一次交换 ad : mamda
第二次交换 md : madma
第三次交换 ma : madam (回文!完美!)
输入格式
第一行是一个整数N,表示接下来的字符串的长度(N <= 8000)
第二行是一个字符串,长度为N.只包含小写字母
输出格式
如果可能,输出最少的交换次数。
否则输出Impossible
样例输入
5
mamad
样例输出
3
写贪心的三步走了解一下:
第一步
明确到底什么是最优解?
------------>字符串通过有限的交换变成回文串,最小的交换次数 。
第二步
明确什么是子问题的最优解?
------------>把字符串中的一个字母使得相对字符串对称的位置出现同样的字母,最小的交换次数。
第三步
分别求出子问题的最优解再堆叠出全局最优解。
AC代码登场:
第一种:
#include<bits/stdc++.h>
using namespace std;
int main(){
int N;
string s;
cin>>N>>s;
int flag=0;
int sum=0;
for(char i='a';i<='z';i++){
sum=count(s.begin(),s.end(),i);
if(sum%2!=0)flag++;
}
if(flag>=2){
cout<<"Impossible"<<endl;
return 0;
}
flag=0;
sum=0;
int dex=-1;
for(int i=0;i<(N-1)/2;i++){
dex=s.rfind(s[i],N-1-i+flag);
if(dex==i){
flag++;
sum+=(N-1)/2-i;
}
else{
for(int j=dex;j<N-1-i+flag;j++){
swap(s[j],s[j+1]);
sum++;
}
}
}
//cout<<s<<endl;
cout<<sum<<endl;
return 0;
}//完结撒花
第二种:
#include <stdio.h>
int main(){
int n,sum=0;
int flag=0;
char a[8001];
scanf("%d",&n);
scanf("%s",a);
int i,j=n-1,k,m;
for(i=0;i<j;i++){
for(k=j;k>=i;k--){
if(i==k){ //利用贪心思想,找到与a[i],相同的字符,如果i==k了 ,那就是没有找到相同的字符;
if(n%2==0){//如果n是偶数个字符的话,那就不能构成回文数
printf("Impossible");
return 0;
}
else{
if(flag){
printf("Impossible");
return 0;
}
}//如果是奇数的话就要把他移动到中间
sum+=(n/2)-i;
flag=1;
break;
}
if(a[i]==a[k]){//如果找到与a[i]相同的字符,则进行交换
for(m=k;m<j;m++){
a[m]=a[m+1];
sum++;
}
a[j]=a[i];
--j;
break;
}
}
}
printf("%d",sum);
return 0;
} // 内有批注
//完结撒花