优先队列专题 poj 2431 2442 3190 1442 3614

来源:互联网 发布:python google earth 编辑:程序博客网 时间:2024/05/18 12:33

优先队列:
一种灵活的数据结构,经常和贪心算法结合使用,并且比较适合于动态的相关算法。

POJ2431

题意:有n个加油站,给出含有的油的量和与目的地的距离,每单位油能走每单位的距离,判断是否能走完全路程,如果能走完给出,需要的最少的加油站的数目;

模拟题,但是需要使用优先队列(最大值),模拟每次经过加油站都把油加入优先队列之中。如果路上没有油了,就取出优先队列中的最大值“使用”,进行模拟但是需要注意各种边界条件。

struct Node{    int len;    int has;    Node(int i,int j):len(i),has(j){}};bool operator<(const Node&n1,const Node&n2){return n1.has<n2.has;}struct cmp2{    bool operator ()(int &a,int &b){        return a<b;//最大值优先    }};
  • 注意:对于一个节点,规定了<号,那么是最大值优先(默认)

  • 默认的int也是最大值优先

  • 最小值优先

priority_queue<int,vector<int>,greater<int>> p;

POJ2442

题意:给出m行每行有n个数,每行选择一个数,理论上有m^n种选择方法,求出这些方法中和最小的n个。

1.将第一序列读入data1向量中,并按升序排序。
2.将数据读入data2向量中,并按升序排序。
将data2[0] + data1[i] ( 0<=i<=n-1)读入dataq向量中
用make_heap对dataq建堆。
然后data2[1] + data1[i] (0<=i<=n-1),如果data2[1] + data1[i]比堆dataq的顶点大,则退出,否则删除
堆的顶点,插入data2[1] + data1[i]。然后是data2[2],…data2[n - 1]
3.将dataq的数据拷贝到data1中,并对data1按升序排序
4.循环2,3步,直到所有数据读入完毕。
5.打印data1中的数据即为结果。

#include<stdio.h>#include<iostream>#include<algorithm>#define N 2000+7using namespace std;int n,m;int a[N];int b[N];int aid[N];int main(){    //freopen("D://in.txt","r",stdin);    int cases;    scanf("%d",&cases);    while(cases--){      scanf("%d%d",&m,&n);      if(m==1){          for(int i=0;i<n;i++){              scanf("%d",&a[i]);          }          sort(a,a+n);      }else{          for(int lines=0;lines<m;lines++){              if(lines==0){                  for(int i=0;i<n;i++){                      scanf("%d",&a[i]);                  }                  sort(a,a+n);              }else{                  for(int i=0;i<n;i++){                      scanf("%d",&b[i]);                  }                  sort(b,b+n);                  for(int i=0;i<n;i++){                      aid[i]=b[0]+a[i];                  }                  make_heap(aid,aid+n);                  for(int i=1;i<n;i++){                      for(int j=0;j<n;j++){                          int tmp=b[i]+a[j];                          if(tmp<aid[0]){                              pop_heap(aid,aid+n);                              aid[n-1]=tmp;                              push_heap(aid,aid+n);                          }                      }                  }                  for(int i=0;i<n;i++){                      a[i]=aid[i];                  }                  sort(a,a+n);              }          }      }      for(int i=0;i<n;i++){          cout<<a[i]<<" ";      }cout<<endl;    }}
  • 思路很重要;为什么不直接在原来的a上建堆,而是又开辟了辅助数组aid:因为比较堆顶元素和a[i]+b[j]的时候会因为a数组的元素改变产生错误。

  • 相当于一个逐渐替换的过程,首先全部选择的是第一个元素,然后分别用后面的替换原来堆中最大的。

POJ3190

题意:
每头牛的挤奶时间是【a,b】需要占用一个工具,如何安排牛的挤奶时间,让需要的工具最少。
维护一个优先队列(小),是每个区间的结束时间;
对月每一头牛的开始时间,如果比堆顶的时间还要早说明,需要一个工具,否则的话,更新这个堆顶的时间为这头牛的结束时间。
统计堆的大小,就是需要的工具个数

POJ1442

题意:
动态的添加元素和查询
第一次查询是第1小的元素,第二次查询是第二小的元素……

代码

放入元素的代码

            minHeap.push ( array[k] );            if ( ! maxHeap.empty() && minHeap.top() < maxHeap.top() ){                t1 = minHeap.top(); minHeap.pop();                t2 = maxHeap.top(); maxHeap.pop();                maxHeap.push(t1); minHeap.push(t2);            }

第i次查找第i大的元素,因此,只要保证两个堆的大小是动态变化的即可
每次查找的元素都在小顶堆的堆顶,用完之后,将其放入大顶堆

        printf("%d\n",minHeap.top());        maxHeap.push ( minHeap.top() );        minHeap.pop();

POJ3614

题意:奶牛美容:有C头奶牛日光浴,每头奶牛分别需要minSPF_i和maxSPF_i单位强度之间的阳光。现有L种防晒霜,分别能使阳光强度稳定为SPF_i,其瓶数为cover_i。求最多满足多少头奶牛

可以直接贪心

int n,m;struct Node{    int b,e;    Node(int b,int e):b(b),e(e){}    Node(){}};struct SPF{    int val,num;    SPF(int val,int num):val(val),num(num){}    SPF(){}};bool cmp(const Node&n1,const Node&n2){    if(n1.b<n2.b)return true;    else if(n1.b>n2.b)return false;    else return n1.e>n2.e;}bool cmp2(const SPF&n1,const SPF&n2){return n1.val<n2.val;}Node a[N];int mark[N];SPF b[N];int main(){     scanf("%d%d",&n,&m);    for(int i=0;i<n;i++){scanf("%d%d",&a[i].b,&a[i].e);}    for(int i=0;i<m;i++){scanf("%d%d",&b[i].val,&b[i].num);}    sort(a,a+n,cmp);    sort(b,b+m,cmp2);    for(int i=0;i<m;i++){//对于每一个给定的防晒霜的值        for(int num=0;num<b[i].num;num++){//对于每一个防晒霜的数量            int index=-1;            int miner=INF;            for(int k=0;k<n&&a[k].b<=b[i].val;k++){                if(mark[k]==0&&a[k].e>=b[i].val){                    if(a[k].e<miner){                        miner=a[k].e;                        index=k;                    }                }            }            mark[index]=1;        }    }    int sum=0;    for(int i=0;i<n;i++){sum+=mark[i];}    cout<<sum<<endl;}

显然有更好的解决方案:
对于满足题意的奶牛,可以让其按照区间右端点的最小值优先进入优先队列,然后不断的从队列中出来ni个数,ni是当前防晒霜的数量。

0 0
原创粉丝点击