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

有一段时间没有用c++写过程序了,偶尔心血来潮刷两道水题,没想到居然被一道题卡住了。。。。很难受emmmm

写出来给大家分享下,觉得这道题挺精妙的,有值得学习的地方(大神可忽略)

题目如下:

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

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

  例如mamad

  第一次交换 ad : mamda

  第二次交换 md : madma

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

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

  否则输出Impossible 样例输入 5

mamad 样例输出 3

看上去并不难,一开始我的思路也正确,先假设前面的不动,从后往前遍历字符串,遇到相同的字符则移动到对应位置,并记录下移动的次数。

可是我却被中间那个字符卡住了,字符串长度是偶数很好办,奇数则会多出一个字符不需匹配,放在中间即可,原本我的思路是先给一次机会,遇到匹配不成功的则移到中间(奇数情况下),可是接下来继续匹配的时候又出了问题,由于操作字符串,那个单独的字符产生了偏移,不在中间了。

于是我又把它操作了回去,结果一来一回多走了两次。。。

好在最终我想出了办法,就是先忽略这个特殊字符,继续匹配直到完成,最后再来处理它,代码如下:

#include<cstdio>
#include<string>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cctype>
#include<cmath>
using namespace std;
int main()
{
 string str;
 int n,j,cnt=0,flag=0,index;          //cnt为移动次数,flag记录唯一一次不匹配的机会
 cin>>n>>str;
 int last=n-1;                 //last很关键,记录了未完成匹配那部分字符串的末位
 for(int i=0;i<last;i++)
 {
     for(j=last;j>i;j–)
     {
         if(str[i]==str[j])
         {
         for(int u=j;u<last;u++)
         str[u]=str[u+1];
        str[last]=str[i];
        cnt+=last-j;
        –last;
        break;
         }
     }
     if(j==i&&(n%2==0||flag==1))   //如果匹配不到且(字符串长度为偶数或者机会用完),那么再见
     {
         cout<<“Impossible”<<endl;
         return 0;
     }
     else if(j==i)     //使用不匹配的那次机会,并记录特殊字符的位置
     {
         flag=1;
         index=i;
     }
 }
 if(flag==0)
 cout<<cnt<<endl;
 else
 cout<<cnt+n/2-index<<endl;    //将不匹配的特殊字符移到中间(因为求次数所以直接修改cnt即可)
 return 0;
}

这样问题就解决了,先忽略那个特殊字符不进行处理的方法的确挺巧妙,值得一记。

    原文作者:贪心算法
    原文地址: https://blog.csdn.net/langzitan123/article/details/79645081
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞