堆 POJ - 2010  优先队列 (错误二分)

这是一道利用优先队列预处理的一道题.
网上有一些二分的题解,但是是错的.
对于每个中位数,我们对于其前面的n/2个数,并用优先队列预处理.size大于n/2时pop掉学费最贵的.
后n/2也是这么预处理的
最后只要到过来找第一个成立的即可,否则就是-1

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
const int maxn = 1e5+30;
const int inf = 0x3f3f3f3f;
using namespace std;
int n,c,f;
int half;
pair<int, int>cow[maxn];
int lower[maxn], upper[maxn];

void init(int st, int ed, int *a){
    int total = 0;
    priority_queue<int>q;
    bool flag = st<ed;
    if(flag){
        for(int i = st; i < ed; i++){
            a[i] = (q.size() == half? total:inf);
            q.push(cow[i].second);
            total += cow[i].second;
            if(q.size() > half){
                total -= q.top(); q.pop();
            }
        }
    } else {
        for(int i = st; i >= ed; i--){
            a[i] = (q.size() == half? total:inf);
            q.push(cow[i].second);
            total += cow[i].second;
            if(q.size() > half){
                total -= q.top(); q.pop();
            }
        }
    }
}

int main() {
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    while(~scanf("%d%d%d",&n,&c,&f)) {
        half = n/2;
        for(int i = 0; i < c; i++) {
            scanf("%d%d",&cow[i].first, &cow[i].second);
            /*
            if(cow[i].second > f) {
                i --;
                c --;
            }
            */
        }
        sort(cow, cow+c);
        //预处理
        init(0, c, lower);
        init(c-1, 0, upper);
        //
        int ans = -1;
        for(int i = c-1; i >= 0; i--) {
            if(lower[i] + cow[i].second + upper[i] <= f) {
                ans = cow[i].first;
                break;
            }
        }
        cout << ans << endl;
    }
    return 0;
}

二分代码:
错在不能保证mid左右两个区间至少有一个区间内是全满足的,但是如果我们mid就不成立,那么下面的区间缩小根本不能进行.而数据竟然弱到可以wa掉二分的.
数据:
3 5 17
1 2
7 2
8 16
9 13
11 15
ans = 7
以下为错误代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#define ll long long
const int maxn = 1e5+30;
using namespace std;

int n,c,f;
int ans;
struct cow{
    int score, aid, rak;
    cow() {}
    cow(int score, int aid): score(score), aid(aid){}
}cows[maxn],cowa[maxn];

bool cmp_score(cow a, cow b){
    if(a.score == b.score)return a.aid < b.aid;
    return a.score < b.score;
}

bool cmp_aid(cow a, cow b){
    if(a.aid == b.aid)return a.score < b.score;
    return a.aid < b.aid;
}

int main () {
    ios::sync_with_stdio(false);cout.tie(0);
    while(~scanf("%d%d%d",&n,&c,&f)){
        for(int i = 0; i < c; i++){
            scanf("%d%d",&cows[i].score, &cows[i].aid);
        }
        sort(cows, cows+c, cmp_score);
        for(int i = 0; i < c; i++){
            cows[i].rak = i;
        }
        memcpy(cowa, cows, sizeof cows);
        sort(cowa, cowa+c, cmp_aid);
        int l = 0, r = c, mid;
        ans = -1;
        //二分中间值
        while(r>l+1){
            mid = (l+r)>>1;
            int left = 0, right = 0, total = cows[mid].aid;
            //贪心的选取
            for(int i = 0; i < c ; i++){
                if((cowa[i].rak < mid) && (total + cowa[i].aid <= f) && (left < n/2)){
                    total += cowa[i].aid;
                    left++;
                }else if((cowa[i].rak > mid) && (total + cowa[i].aid <= f) && (right < n/2)){
                    total += cowa[i].aid;
                    right++;
                }
            }
            if((left < n/2) && (right < n/2)){
                ans = -1;break;
            }else if(left < n/2){
                l = mid;
            }else if(right < n/2){
                r = mid;
            }else {
                ans = cows[mid].score;
                l = mid;
            }
        }
        cout << ans << endl;
    }
    return 0;
}

优先队列是由大顶堆实现的.
下面是堆排序的代码.
首先做了一个自下向上的建堆处理
保证节点比其儿子的值更大.
然后就每次把堆顶的数字拿出来与最后的数字兑换,在自上而下的调整.最终实现排序

#include<cstdio>
void maxHeap(int *a,int n,int i)
{
    //left、right、largest分别指向
    //左孩子、右孩子、{a[i],a[left]}中最大的一个
    int left,right,largest;
    largest=left=2*i;
    if(left>n)
        return;
    right=2*i+1;
    if(right<=n && a[right]>a[left]){
        largest=right;
    }
    if(a[i]<a[largest]){//根结点的值不是最大时,交换a[i],a[largest]
        a[i]=a[i]+a[largest];
        a[largest]=a[i]-a[largest];
        a[i]=a[i]-a[largest];
        //自上而下调整堆
        maxHeap(a,n,largest);
    }
}

//建堆
void creatHeap(int *a,int n)
{
    int i;
    //自下而上调整堆
    for(i=n/2;i>=1;i--)
        maxHeap(a,n,i);
}

//堆排序
void heapSort(int *a,int n)
{
    int i;
    creatHeap(a,n);//建堆
    for(i=n;i>=2;i--){
        //堆顶记录和最后一个记录交换
        a[1]=a[1]+a[i];
        a[i]=a[1]-a[i];
        a[1]=a[1]-a[i];
        //堆中记录个数减少一个,筛选法调整堆
        maxHeap(a,i-1,1);
    }
}
int main()
{
    int i;
    int a[7]={0, 5,1,7,9,8,2};//不考虑a[0]
    heapSort(a,6);
    for(i=1;i<=6;i++)
        printf("%-4d",a[i]);
    printf("\n");
}

如果是node,不能按下面这么写.

priority_queue<Node, vector<Node>, greater<Node> >;
要把greater改成下面这样的

struct cmp{
    bool operator() ( Node a, Node b ){
        if( a.x== b.x ) return a.y> b.y;

        return a.x> b.x; }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值