算法设计与分析 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;
}

posted on 2019-12-22 01:30  yejifeng  阅读(969)  评论(0编辑  收藏  举报

导航