您的位置:首页 > 编程语言 > C语言/C++

蓝桥杯基础训练1573:完美的代价(C语言实现)

2018-12-05 02:17 375 查看

蓝桥杯基础训练1573:完美的代价(C语言实现)

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

如图:

由此开始,先定义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(void)
{
char a[8001];
bool flag = false;
int n, sum=0;
scanf("%d", &n);
getchar();
gets(a);
int i, j, k, m;
j = n - 1;
for(i=0; i<j; ++i)
for(k=j; k>=i; --k)
{
if(i==k)
{
if(n%2==0)
{
printf("Impossible");
return 0;
}
else
{
if(flag)
{
printf("Impossible");
return 0;
}
}
sum += n/2-i;
flag = true;
break;
}
if(a[i]==a[k])
{
for(m=k; m<j; ++m)
{
a[m] = a[m+1];
sum++;
}
a[j] = a[i];
--j;
break;
}
}
printf("%d", sum);
return 0;
}

如有不足,请多指教,欢迎评论区留言O(∩_∩)O

阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: