贪心算法:所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。
思路:从问题的某一个初始解出发一步一步地进行,根据某个优化测度,每一步都要确保能获得局部最优解。若下一个数据和部分最优解连在一起不再是可行解时,就不把该数据添加到部分解中,直到把所有数据枚举完,或者不能再添加算法停止。如果贪婪算法正确工作,那么找到的第一个解通常是最优的。
应用:
思路:
1.首先判断IMPOSSIBLE的情况
主要分为两种情况:出现2个及以上的奇数个数 & 出现一个奇数但是字符串长度为偶数
2.字符与字符的交换,可以看作是字符的移动。那么相同的字符,为了求得最少的步骤,我们要保证他们的移动方向是一致的,否则比如一个往右移动4位,另一个往左移动2位,其实就是往右移动了两位。
所以我们从字符串的第一位开始,从右往左遍历,看是否有和它相同的字符。如果找到了,下一次就不用管他们了,遍历的end-1;下一次为字符串第二位寻找,从倒数第二位开始遍历。
(这一步应该是贪心思想的应用,遍历的时候找到相同的字符,换就完事儿了!)
3.假如只有一个出现次数为奇数的字符且字符串长度也为奇数,我们要在最后一步才将他移动到字符串的最中央。试想如果一开始就将它移动到字符串中央,则在他之后其它字符的移动都要加一步,步数变多。所以找到了这个数,直接将cnt加上其所在位置与中间位置的差距即可。
// 以下是代码,感谢网上诸位大佬的优秀思路借鉴!
#include <iostream>
#include <string>
#include<cstring>
#include<iostream>
using namespace std;
int main(){
int n;
string a;
while(cin>>n){
cin>>a;
int cnt = 0,flag = 0,f2=0,l=n-1; //用于判断字符串中出现次数为奇数的字母的个数
//f2是不知道如何打破两个循环而加的奇奇怪怪的东西...
for(int i = 0;i<l;i++){
for(int j = l;j>=i;j--){
if(i==j){
if(n%2==0 || flag==1){ //不可能条件:出现2个及以上的奇数个数&一个奇数但是字符串长度为偶数
cout<<"Impossible"<<endl;
f2 = 1;
break;
}
cnt += n / 2 - i; //将次字符交换到中间位置的次数
flag=1;
}
else if(a[i]==a[j]){
for (int k = j; k < l; k++){ //交换相邻两个位置的字符
swap(a[k], a[k+1]);
cnt++;
}
l--;
break;
}
}
if(f2) break;
}
if(f2==0) cout<<cnt<<endl;
}
}