码迷,mamicode.com
首页 > 其他好文 > 详细

蓝桥杯基础练习 完美的代价

时间:2018-03-09 19:03:18      阅读:170      评论:0      收藏:0      [点我收藏+]

标签:输出   字符串   ...   贪心算法   第一个字符   mes   pre   输入   数组   

问题描述
  回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。
  交换的定义是:交换两个相邻的字符
  例如mamad
  第一次交换 ad : mamda
  第二次交换 md : madma
  第三次交换 ma : madam (回文!完美!)
输入格式
  第一行是一个整数N,表示接下来的字符串的长度(N <= 8000)
  第二行是一个字符串,长度为N.只包含小写字母
输出格式
  如果可能,输出最少的交换次数。
  否则输出Impossible
样例输入
5
mamad
样例输出
3
解题思路:
求最少的交换次数,考虑用贪心算法,当一个字符不动,另一个字符移动到对称位置时移动步数最少。
有字符个数为奇数和偶数两种情况:
  1. 字符个数为偶数,不能有不对称的字符。
  2. 字符个数为奇数,没有对称字符的字符只能有一个,设变量flag来标记是不是第一次不对称。

另外需要注意:

  奇数情况下若找到不对称字符,不能先移动它,将移动至中间所需要的步数加入总步数即可,可以想象第一个字符为非对称字符的情况代入程序中,非对称字符移动到中间,使得第二个字符变成第一个字符,但是外循环已经跳过了第一个字符(如果要先移动非对称字符,则移动后需要从上一个位置重新计算)。

 
#include <iostream>
#include <cstdio>
using namespace std;

int main()
{
    char str[8001];
    int n, end, j, k, cnt=0, flag=1;
    cin>>n;getchar();
    for(int i=0; i<n; i++)
        scanf("%c", &str[i]);
    end = n-1;    //end为最后一个字符下标 
    //从头开始遍历
    for(int i=0; i<end; i++)
    {
        //从末尾开始遍历
        for(j=end; j>=i; j--)
        {
            //找不到相同的字符 
            if(i == j)
            {
                //判断不是第一次找不到匹配的字符 或 n为偶数
                if(flag==0 || n%2==0)
                {
                    //返回impossible
                    printf("Impossible\n");
                    return 0;    
                }
                //是第一次找不到且n为奇数,则将flag变为0,计算应该移动多少位(n/2-j)但不要真的移动
                /*
                *不匹配的字符如果在数组的后半部分则当其他位置匹配时必然n/2==j,
                *即不需要移动,如果在前半部分则需要移动n/2-j,当然减i也行(此时i==j) 
                */
                else 
                {
                    flag = 0; 
                    cnt += n/2-i; 
                }
            }
            //找到相同的字符
            else if(str[j] == str[i])
            {
                //将该位置的字符与向后相邻的字符交换,直到end
                for(k=j; k<end; k++)//注意不能连end也算入,k+1已经替换了end 
                {
                    swap(str[k], str[k+1]);
                    cnt++;
                }
                //end向前移动一位(因为该位置已经对称) 
                end--;
                break;
            }
            
        }    
    }
    cout<<cnt<<endl; 
    
    return 0;
}

/*注:
程序中的判断是否找到相同字符if... else if...位置不可交换,因为i==j时,
必然str[i]==str[j],但是这是找不到的情况 
*/

 

蓝桥杯基础练习 完美的代价

标签:输出   字符串   ...   贪心算法   第一个字符   mes   pre   输入   数组   

原文地址:https://www.cnblogs.com/kamicoder/p/8535214.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!