1. 程式人生 > >優先佇列 C++STL——優先佇列

優先佇列 C++STL——優先佇列

C++STL——優先佇列

 

一、相關定義

優先佇列容器與佇列一樣,只能從隊尾插入元素,從隊首刪除元素。但是它有一個特性,就是佇列中最大的元素總是位於隊首,所以出隊時,並非按照先進先出的原則進行,而是將當前佇列中最大的元素出隊。這點類似於給佇列裡的元素進行了由大到小的順序排序。元素的比較規則預設按元素值由大到小排序,可以過載“<”操作符來重新定義比較規則。

優先順序佇列可以用向量(vector)或雙向佇列(deque)來實現(注意list container不能用來實現queue,因為list的迭代器不是任意存取iterator,而pop中用到堆排序時是要求randomaccess iterator 的!):
priority_queue<vector<int>, less<int> > pq1;     // 使用遞增less<int>函式物件排序
priority_queue<deque<int>, greater<int> > pq2;   // 使用遞減greater<int>函式物件排序
其成員函式有“判空(empty)” 、“尺寸(Size)” 、“棧頂元素(top)” 、“壓棧(push)” 、“彈棧(pop)”等。

 

二、priority_queue

基本操作:

empty()      如果佇列為空,則返回真

pop()    刪除對頂元素,刪除第一個元素

push()        加入一個元素

size()      返回優先佇列中擁有的元素個數

top()     返回優先佇列對頂元素,返回優先佇列中有最高優先順序的元素

在預設的優先佇列中,優先順序高的先出隊。在預設的int型中先出隊的為較大的數。

標頭檔案:

#include <queue>

宣告方式:

1、普通方法:

priority_queue<int> q;                 //通過操作,按照元素從大到小的順序出隊 priority_queue<int,vector<int>, greater<int> > q;    //通過操作,按照元素從小到大的順序出隊

2、自定義優先順序:

struct cmp {        operator bool ()(int x, int y)        {              return x > y;   // x小的優先順序高       //也可以寫成其他方式,如: return p[x] > p[y];表示p[i]小的優先順序高   } }; priority_queue<int, vector<int>, cmp> q;    //定義方法 //其中,第二個引數為容器型別。第三個引數為比較函式。

3、結構體宣告方式:

struct node {        int x, y;        friend bool operator < (node a, node b)        {              return a.x > b.x;    //結構體中,x小的優先順序高        } }; priority_queue<node>q;   //定義方法 //在該結構中,y為值, x為優先順序。 //通過自定義operator<操作符來比較元素中的優先順序。 //在過載”<”時,最好不要過載”>”,可能會發生編譯錯誤   題: 6 2 10 3 12 15 12 18 6 1 10 3 12 15 12 18 5 5 1 2 3 4 5 Sample Output 37 25 15 題意: 有6個點,分別是第二行的六個數,代表房間的價格;你每k(第一個樣例中的2)就會有一天可以免費,問怎麼樣能使花的錢最少,必須依次住,不能跳著住。   思路1: 第一個樣例: 前兩天一定要選,所以可以刪除一個,從第k+1天到能刪第二個數中,找一個最大的數放在佇列(不一定刪除,因為可能後面有比他大的數,因為佇列空所以不用替換),之後每一個i%(k+1)!=0的數,都要和佇列中最小的數比較,如果這個數大於佇列中的最小的,就替換掉(其實第一次也一樣,只不過第一次的時候佇列為空),如果i%(k+1)==0,就先把他放進佇列,然後就進入上面的情況中。 程式碼如下:
#include <iostream>
#include<algorithm>
#include<math.h>
#include<cstring>
#include<cstdlib>
#include<queue>
using namespace std;
typedef long long ll;
int a[100010];
int main()
{
    ll n,k,sum=0;;
    priority_queue<int,vector<int>,greater<int> >q;
    while(~scanf("%lld",&n))
    {
        sum=0;
        scanf("%lld",&k);
        for(int i=1; i<=n; i++)
        {
             scanf("%d",&a[i]);
             sum+=a[i];
        }

        for(int i=k+1;i<=n;i++)
        {
            if(i%(k+1)!=0)
            {
                if(q.top()<a[i])
                {
                    q.pop();
                    q.push(a[i]);
                }
            }
            else 
            {
                q.push(a[i]);
            }
        }
        while(q.size()!=0)
        {
            sum-=q.top();
            q.pop();
        }
        printf("%lld\n",sum);

    }
    return 0;
}

 

思路2: 這個思路差不多,從後面開始入佇列,如果i%(k+1)==0,找佇列中的最大的刪掉。
#include <iostream>
#include<algorithm>
#include<math.h>
#include<cstring>
#include<cstdlib>
#include<queue>
using namespace std;
typedef long long ll;
int a[100010];
int main()
{
    ll n,k,sum=0;;
    priority_queue<int,vector<int>,less<int> >q;
    while(~scanf("%lld",&n))
    {
        sum=0;
         scanf("%lld",&k);
         for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        while(q.size()!=0)
        {
            q.pop();
        }
         for(int i=n;i>=1;i--)
         {
             q.push(a[i]);
             if(i%(k+1)==0)
             {
                q.pop();
             }
         }
         while(q.size()!=0)
         {
             sum+=q.top();
             q.pop();
         }
         printf("%lld\n",sum);
    }
    return 0;
}

 

一、相關定義

優先佇列容器與佇列一樣,只能從隊尾插入元素,從隊首刪除元素。但是它有一個特性,就是佇列中最大的元素總是位於隊首,所以出隊時,並非按照先進先出的原則進行,而是將當前佇列中最大的元素出隊。這點類似於給佇列裡的元素進行了由大到小的順序排序。元素的比較規則預設按元素值由大到小排序,可以過載“<”操作符來重新定義比較規則。

優先順序佇列可以用向量(vector)或雙向佇列(deque)來實現(注意list container不能用來實現queue,因為list的迭代器不是任意存取iterator,而pop中用到堆排序時是要求randomaccess iterator 的!):
priority_queue<vector<int>, less<int> > pq1;     // 使用遞增less<int>函式物件排序
priority_queue<deque<int>, greater<int> > pq2;   // 使用遞減greater<int>函式物件排序
其成員函式有“判空(empty)” 、“尺寸(Size)” 、“棧頂元素(top)” 、“壓棧(push)” 、“彈棧(pop)”等。

 

二、priority_queue

基本操作:

empty()      如果佇列為空,則返回真

pop()    刪除對頂元素,刪除第一個元素

push()        加入一個元素

size()      返回優先佇列中擁有的元素個數

top()     返回優先佇列對頂元素,返回優先佇列中有最高優先順序的元素

在預設的優先佇列中,優先順序高的先出隊。在預設的int型中先出隊的為較大的數。

標頭檔案:

#include <queue>

宣告方式:

1、普通方法:

priority_queue<int> q;                 //通過操作,按照元素從大到小的順序出隊 priority_queue<int,vector<int>, greater<int> > q;    //通過操作,按照元素從小到大的順序出隊

2、自定義優先順序:

struct cmp {        operator bool ()(int x, int y)        {              return x > y;   // x小的優先順序高       //也可以寫成其他方式,如: return p[x] > p[y];表示p[i]小的優先順序高   } }; priority_queue<int, vector<int>, cmp> q;    //定義方法 //其中,第二個引數為容器型別。第三個引數為比較函式。

3、結構體宣告方式:

struct node {        int x, y;        friend bool operator < (node a, node b)        {              return a.x > b.x;    //結構體中,x小的優先順序高        } }; priority_queue<node>q;   //定義方法 //在該結構中,y為值, x為優先順序。 //通過自定義operator<操作符來比較元素中的優先順序。 //在過載”<”時,最好不要過載”>”,可能會發生編譯錯誤   題: 6 2 10 3 12 15 12 18 6 1 10 3 12 15 12 18 5 5 1 2 3 4 5 Sample Output 37 25 15 題意: 有6個點,分別是第二行的六個數,代表房間的價格;你每k(第一個樣例中的2)就會有一天可以免費,問怎麼樣能使花的錢最少,必須依次住,不能跳著住。   思路1: 第一個樣例: 前兩天一定要選,所以可以刪除一個,從第k+1天到能刪第二個數中,找一個最大的數放在佇列(不一定刪除,因為可能後面有比他大的數,因為佇列空所以不用替換),之後每一個i%(k+1)!=0的數,都要和佇列中最小的數比較,如果這個數大於佇列中的最小的,就替換掉(其實第一次也一樣,只不過第一次的時候佇列為空),如果i%(k+1)==0,就先把他放進佇列,然後就進入上面的情況中。 程式碼如下:
#include <iostream>
#include<algorithm>
#include<math.h>
#include<cstring>
#include<cstdlib>
#include<queue>
using namespace std;
typedef long long ll;
int a[100010];
int main()
{
    ll n,k,sum=0;;
    priority_queue<int,vector<int>,greater<int> >q;
    while(~scanf("%lld",&n))
    {
        sum=0;
        scanf("%lld",&k);
        for(int i=1; i<=n; i++)
        {
             scanf("%d",&a[i]);
             sum+=a[i];
        }

        for(int i=k+1;i<=n;i++)
        {
            if(i%(k+1)!=0)
            {
                if(q.top()<a[i])
                {
                    q.pop();
                    q.push(a[i]);
                }
            }
            else 
            {
                q.push(a[i]);
            }
        }
        while(q.size()!=0)
        {
            sum-=q.top();
            q.pop();
        }
        printf("%lld\n",sum);

    }
    return 0;
}

 

思路2: 這個思路差不多,從後面開始入佇列,如果i%(k+1)==0,找佇列中的最大的刪掉。
#include <iostream>
#include<algorithm>
#include<math.h>
#include<cstring>
#include<cstdlib>
#include<queue>
using namespace std;
typedef long long ll;
int a[100010];
int main()
{
    ll n,k,sum=0;;
    priority_queue<int,vector<int>,less<int> >q;
    while(~scanf("%lld",&n))
    {
        sum=0;
         scanf("%lld",&k);
         for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        while(q.size()!=0)
        {
            q.pop();
        }
         for(int i=n;i>=1;i--)
         {
             q.push(a[i]);
             if(i%(k+1)==0)
             {
                q.pop();
             }
         }
         while(q.size()!=0)
         {
             sum+=q.top();
             q.pop();
         }
         printf("%lld\n",sum);
    }
    return 0;
}