题目描述
今年,ThinkSpirit 实验室在 CPC 竞赛上收获颇丰,获得若干金奖、银奖、铜奖。
但是,因为参加了多场比赛,每场比赛的比赛时间不一样,有先后顺序,所以拿回来的奖牌的顺序是按时间顺序排列的,而不是按金银铜奖的顺序排列的。
现在让你帮忙整理奖牌,使得它们按照金银铜奖的顺序重薪排列,即把金奖放在最前面,银奖放在中间,铜奖放在最后面。
值得注意的是,因为奖牌已经摆放好了,所以你只能两两交换其中的奖牌,让它们按照需要的顺序重薪排列,你现在想知道是否存在一个最小的交换次数来完成奖牌的整理工作。
为了便于表示,定义 Au 表示金奖, Ag 表示银奖, Cu 表示铜奖。
输入描述
单组输入,输入共 1 行
一行非空字符串 s ,表示奖牌的顺序,保证字符串中不含空格且字符串长度不大于210^6*
输出描述
输出一个整数,表示重薪排序,完成整理工作所需的最小交换次数。
样例输入 1
AuCuAg
样例输出 1
1
样例输入 2
AgAuAuAgCuAgAuCuCu
样例输出 2
2
样例解释
对于第 1 组样例 AuCuAg ,只要将第 2 个位置上的奖牌与第 3 个位置上奖牌交换即可满足条件,所以输出最小交换次数为 1 。
对于第 2 组样例 AgAuAuAgCuAgAuCuCu ,先将第 5 个奖牌与第 7 个位置上的奖牌交换,再将第 5 个与第 1 个交换即可满足条件,所以输出最小交换次数 2。
解题思路:
我们将字符串转换成123的数字,按照从小到大进行一次排序,跟原来的顺序对比,建立一个有权图,,由 u 指向 v 的边权为 w 边表示有 w 个 u 放在 v 位置。
交换位置只有两种合法的交换,一种是用一次操作对两个交换,另一种是用两次操作对三个顺次交换位置。显然最优解是能互换的先互换,剩下的一定是成一个环,直接环上权乘2累计进答案即可
代码:
#include<bits/stdc++.h>
using namespace std;
string s;
const int N=1e6+5;
int len,n;
int a[N],b[N];
int p[5][5];
int ans,tmp;
int x,y,z;
int main() {
cin >> s;
len = s.length();
n = len/2;
for(int i=0; i<len; i+=2) {
if(s.substr(i,2) == "Au") {
a[i/2] = 1;
} else if(s.substr(i,2) == "Ag"){
a[i/2] = 2;
} else if(s.substr(i,2) == "Cu"){
a[i/2] = 3;
}
b[i/2] = a[i/2];
}
sort(b,b+n);
for(int i=0; i<n; i++) {
for(int x=1; x<=3; x++) {
for(int y=1; y<=3; y++) {
if(b[i] == x && a[i] == y) {
p[x][y]++;
}
}
}
}
tmp = min(p[1][2],p[2][1]);
p[1][2]-=tmp;p[2][1]-=tmp;
ans += tmp;
tmp = min(p[1][3],p[3][1]);
p[1][3]-=tmp;p[3][1]-=tmp;
ans += tmp;
tmp = min(p[2][3],p[3][2]);
p[2][3]-=tmp;p[3][2]-=tmp;
ans += tmp;
tmp = max(p[1][2],p[2][1]);
ans += tmp*2;
printf("%d",ans);
return 0;
}