堆 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; }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章