大体题意:
给你一个字符串,其中R表示红球,B 表示蓝球,其中字符串首尾相连。你可以交换任意相邻的球,问最少交换几次,使得红球在一边,蓝球在一边。
思路:
这个题目比赛没做出来,后来看的学长的博客补得题目。
把RB想成1和0,换一个类似的简单题目来想,如果RB表示的字符串不是一个环,而是一条链的话,那么这个题目就是求逆序对数了,因为交换一次,最多交换一个逆序对,如果你的做法是最优的话,那么每一次交换都可以换一个逆序对,因此如果是一条链的话,那就是逆序对数量。
这个题目需要变通一下,因为是一个环嘛,所以可以把左边的R变成1,B变成0,右边的R变成0,B变成1,这样两边分别求逆序对数,在相加,这就是其中一个答案,最优解答案,就是枚举所有的左右情况,求出最小的答案!
给你一个字符串,其中R表示红球,B 表示蓝球,其中字符串首尾相连。你可以交换任意相邻的球,问最少交换几次,使得红球在一边,蓝球在一边。
思路:
这个题目比赛没做出来,后来看的学长的博客补得题目。
把RB想成1和0,换一个类似的简单题目来想,如果RB表示的字符串不是一个环,而是一条链的话,那么这个题目就是求逆序对数了,因为交换一次,最多交换一个逆序对,如果你的做法是最优的话,那么每一次交换都可以换一个逆序对,因此如果是一条链的话,那就是逆序对数量。
这个题目需要变通一下,因为是一个环嘛,所以可以把左边的R变成1,B变成0,右边的R变成0,B变成1,这样两边分别求逆序对数,在相加,这就是其中一个答案,最优解答案,就是枚举所有的左右情况,求出最小的答案!
具体看代码 分析!
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 100000 + 10;
char s[maxn];
int main(){
int T,cnt = 0;
scanf("%d",&T);
while(T--){
scanf("%s",s);
int len = strlen(s);
int posmid = len >> 1;//求出中间位置!
int inver = 0;//表示从中间分为左右两侧的逆序对答案数!
int tmp[2] = {}; // tmp[0]记录左边R(也就是1)的个数,tmp[1]记录右边B(也就是1)的个数。
for (int i = 0; i < posmid; ++i){
if (s[i] == 'R') ++tmp[0];
else inver += tmp[0];
}
for (int i = posmid; i < len; ++i){
if (s[i] == 'B')++tmp[1];
else inver += tmp[1];
}//以上两个循环,可以求得 从中间一分为二的逆序对数,和 左边1的个数和右边1的个数!
int ans = inver;
for (int i = 0; i < len; ++i){
int t = (posmid + i) % len; // 这样可以用s[t]表示右边的需要加入左边的字符,s[i]表示左边的需要加入右边的字符!
if (s[t] == 'B'){
inver += tmp[0] - (s[i] == 'R');
inver -= (len-posmid-tmp[1]);
}
if (s[i] == 'R'){
inver += tmp[1] - (s[t] == 'B');
inver -= posmid-tmp[0];
}// 以上两个判断 画一个样例图分析一下即可!
if (s[i] == 'R')--tmp[0];
else ++tmp[1];
if (s[t] == 'B')--tmp[1];
else ++tmp[0];// 移动完后 更新左右1的个数!
ans = min(ans,inver);
}
printf("Case #%d: %d\n",++cnt,ans);
}
return 0;
}