算法设计与分析 4.5 洪尼玛与神秘信封
★题目描述
一个仅由“ o ”、“ x ”和“ * ”组成的字符串,将“ * ”替换成“ o ”需要a的代价、替换成“ x ”需要b的代价。
一个字符串合法需要满足以下两个条件:
1.字符串所有前缀的“ o ”的个数必须不小于“ x ”的个数;
2.字符串的“ o ”的个数必须等于“ x ”的个数;
洪尼玛想知道将所有的“ * ”替换成“ o ”或“ x ”使得该字符串合法的最小代价是多少?
如果无解输出-1。
★输入格式
第一行为一个字符串S,表示字符串;
接下来m行,每行两个正整数ai、bi,表示替换成“ o ”、“ x ”所需的代价;
对于60%的数据,字符串长度不大于1000;
对于100%的数据,字符串长度不大于100000,0<=ai、bi<=108。
★输出格式
若有解,输出一个正整数,表示最小代价;
若无解,输出-1。
★样例输入
o**x
1 2
3 5
★样例输出
5
★提示
无
★参考代码
/*
https://blog.csdn.net/f_zyj/article/details/74158391
优先队列优化的贪心问题。
优先队列 + 贪心
1.第一次遍历字符串,把“*”全部用“ x ”替换。在替换过程中记录一下所花代价 sum ,并把 a-b 值加入到一个队列;
2.开始第二次遍历字符串,此时记录 cnt,每当 cnt<0时,表明需要往前面字符串o字符不足,就可以选择队列中的最小的位置替换,等于“*”-> “x”-> “o”,此时 cnt+2、sum+(a-b)
*/
#include<bits/stdc++.h>
using namespace std;
int n;
char S[100005];
int A[100005]={0};
int B[100005]={0};
long long sum = 0; //记录代价
int cnt = 0; //记录o和x的个数差
priority_queue<int> pqi;
long long fun(){
for(int i=0; i<n; ++i){
if(S[i] == 'o') ++cnt;
else if(S[i]=='x' || S[i]=='*') --cnt;
if(S[i]=='*') pqi.push(B[i]-A[i]); //替换时,a[i] - b[i],考虑优先出来大的,故取反
if(cnt < 0) {
if(pqi.empty()) return -1;
sum -= pqi.top();
pqi.pop();
cnt += 2;
}
}
if (cnt != 0) return -1;
return sum;
}
int main(){
scanf("%s", S);
n = (int)strlen(S);
for(int i=0; i<n; ++i){
if(S[i]=='*'){
scanf("%d%d",&A[i],&B[i]);
sum += B[i];
}
}
printf("%lld\n", fun());
return 0;
}