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

Today来分享一下完美的代价

我在做的时候发现了一位up主写的很好,我加一点自己的理解帮助萌新能够完全理解,简直就是保姆级别的教学

首先是题目

 

解析:本题妙用了————贪心(如果不了解可以直接看下面的举例)

如图:

 

由此开始,先定义i,k,两个变量,i 从字符串最左边开始往右遍历,k则从最右边开始往左遍历

 


i 先不改变,让k自减往左遍历(k - -),如果a[ i ] 和 a[ k ]不一样,则k继续往左遍历,直到和a[ i ]一样,如下


定义一个变量 j 等于字符长度(可以理解为一直指最后一个未经过交换对称的字符),则下标最大可到 j-1
则将a[ k ]移动到于a[ i ]对称的位置,可以通过a[ k ] = a[ k+ 1]进行交换,条件为k < j , 最后 a[ j ] = a[ i ]即可,并且在此过程,可以定义一个记录交换次数的变量sum=0,每次交换都进行自增(sum++),由于交换放置后的字符已经形成对称,所以无需改变其位置,下一次下一组字符的交换无需到达该位,可以让 j = j - 1,如下 ,j 原指a,a已经是交换对称了,可以忽略,j指向前一个,i++,接下来只需考虑红框内的字符数组,交换好的无需再管。

在这里插入图片描述 

 


每一轮都让k==j,这保证了k每次都从未经对称的末尾字符开始往左遍历,接下来k遇到m,然后交换,a[ k ] = a[ k+1] ,条件为k < j,最后a[ j ] == a[ i ]即可,和上一步一样的方法,以此类推。

但是,如果一直找不到相等的字符,怎么办?

在这里插入图片描述
像这种情况,如果一直找不到相同的,最后会遇到 i==k 的情况,当i == k的时候,我们可以知道 a[ i ]在数组内独一无二,我们是不是可以把它移动到中间,共移动(数组长度/2 - i)次,这个时候可以不需要真的进行交换,并无影响结果(因为独一无二数放在中间后,由于是经过对称移动的,所以并不能动其位置,所以可以忽略,就和没移动一个样,交换的时候也要跳过,因此不必进行这一交换步骤)。

在这里插入图片描述 

 

如果出现两次 i = = j的情况,则代表数组内存在两个独一无二的字符,不可能存在完美列,可以结束程序,打印Impossible,

当条件 i < j 不满足的时候,代表对称交换已经执行完毕,可以输出sum总值。

代码如下:

#include<stdio.h>
#include<stdlib.h>
int main()
{
    int i,j,k,sum=0,N,t;
    char f[8001];
    scanf("%d",&N);
    scanf("%s",f);
    t=N-1;
    bool flag=false; 
    for(i=0;i<t;i++)
    {
        for(j=t;j>=i;--j)
        {
            if(i==j)
            {
                if(N%2==0||flag)//如果N为偶数但是f[i]又是唯一的字母  flag判断有两次与f[i]相同的字符
                {
                    printf("Impossible");
                    return 0;
                }
                else
                sum+=N/2-i;//f[i]移动至中间所需要的次数
                flag=true;//只有自身相等
                break;
            }
            if(f[i]==f[j])
            {
                for(k=j;k<t;k++)
                {
                    f[k]=f[k+1];
                    sum++;
                }
                f[k]=f[i];
                --t;
                break;
            }
        }
    }
    printf("%d",sum);
    return 0;
 } 

这是那位博主文章的链接,有需要可以看看(19条消息) 蓝桥杯基础训练1573:完美的代价(C语言实现)_厌笑的小鸡蛋-CSDN博客_c语言完美的代价代码

还有不懂的可以评论区问我哟

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值