二叉堆例题解题报告代码--poj3253、poj2442、poj2010、poj3481
来源:互联网 发布:淘宝运营工资大概多少 编辑:程序博客网 时间:2024/05/24 07:36
poj3253 类似于哈夫曼树,每次选择所有数中最小的两个,所以这里要建造小根堆,并删除最小的两个数,然后求这两个数的和之后再插入,这里用二叉堆的 make_heap(开始要建堆)、heap(中间要调整)、push_heap(要把和插入,但是对于这里,可以简单的求和,放入堆顶,然后调整一下就ok)、pop_heap(对于选择的数删除)
#include <stdio.h>#define ll long long#define MAX 20002int n;int a[MAX];void heap(int m){ int t; while(m*2 <= n) { m *= 2; if(m+1 <= n && a[m]>a[m+1]) m ++; if(a[m] < a[m/2]) { t = a[m]; a[m] = a[m/2]; a[m/2] = t; } else break; }}int main(){ scanf("%d",&n); for(int i = 1; i <= n; i ++) scanf("%d",&a[i]);//建堆 for(int i = n/2; i > 0; i --) heap(i); ll ans = 0,pre; while(n > 1) { //选择第一个,并且删除 pre = a[1]; a[1] = a[n]; n--; heap(1);//再选择第一个 pre += a[1];//把和放入堆顶 接着调整 a[1] = pre; heap(1); ans += pre;//求答案 } printf("%I64d\n",ans); return 0;}
poj2442 题意:有m个序列,每个序列n个数,我们在每个序列中选一个数,那么就有m个数,对应这m个数有一个和,那么对于所有的数,总共有m^n个选法,要求从小到大输出其中最下的n个选法的和
分析:直接暴力时间复杂度太高,这里用到一点dp,对于m个序列,先求出第k-1项序列的n个数,放于A数组,每个数都是k-1个数的和,那么对于第k个序列,把这个序列的第一个和A数组的每一个相加放到B数组,然后把第k个序列的每一个都和A数组的每一个数相加,然后和B中的最大数相比较,如果小,就互换(因为要n个最小的),具体处理如下(用到滚动数组)操作中只要用到一个heap,和最开始的一个make_heap:
//180K 1922MS#include <cstdio>#include <algorithm>using namespace std;#define MAX 2002int n,m;int a[2][MAX]; //滚动数组void heap(int r[],int m){ int t; while(m*2 <= n) { m *= 2; if(m +1 <= n && r[m] < r[m+1]) m ++; if(r[m] > r[m/2]) { t = r[m/2]; r[m/2] = r[m]; r[m] = t; } else break; }}int main(){ int T; int t,flag; scanf("%d",&T); while(T --) { flag = 0; scanf("%d%d",&m,&n); for(int i = 1; i <= n; i ++) scanf("%d",&a[0][i]); for(int i = n/2; i > 0; i --) heap(a[flag],i); //首先我们把第一个序列建堆 for(int i = 2; i <= m; i ++,flag = 1-flag) { scanf("%d",&t); for(int j = 1; j <= n; j ++) a[1-flag][j] = a[flag][j] + t;//把下一个序列的第一个与上一个序列每一个相加得一个新的序列,也具有堆性质 for(int j = 1; j < n; j ++)//对于这个序列的剩下 n-1个数 与 A 中每一个相加再与 B 的最大比较 { scanf("%d",&t); for(int k = 1; k <= n; k ++) { if(a[flag][k] + t < a[1-flag][1]) { a[1-flag][1] = a[flag][k] + t; heap(a[1-flag],1); //这里就用到堆的性质 } } } } sort(a[flag]+1,a[flag] + n+1); //排序输出 for(int i = 1; i <= n; i ++) { printf(i==1 ? "%d":" %d",a[flag][i]); } printf("\n"); } return 0;}
poj2010 题意:这里有C头牛,每头牛有一个考试分数,和需要资助的钱,我们选择其中的N头牛资助,并且我们只有F的钱,而且我们有一个要求,就是选择的这N头牛,我们需要他们的分数的中位数 最大
处理:既然要分数的中位数,我们就先按照sorce从小到大排序,由于要N个,那么选择第k个牛,前面就有N/2个之后也有N/2个,那么我们只要枚举第N/2~C-N/2的牛即可,又因为要中位数最大,我们就从右到左一一枚举,如果当前这头牛满足条件,那么这头牛的分数就是答案
那么对于满足要求这个条件,我们分别为1~N/2和C-N/2~C 维护left 和right 两个最大堆,left_sum 和 right_sum分别记录左右堆的 和,由于枚举过程中从右到左,那么对于左边的 left需要预处理,left[1]~left[N/2]为维护的对,left[N/2+1]~left[C-N/2] 其中的每个left[i] 表示 枚举i 这头牛的时候,左边选择的N/2头牛的最小资助金和
对于每个点i,left[i]+right_sum+cow[i].fa <= F,就是我们的满足要求
对于每个点i,left[i]+right_sum+cow[i].fa <= F,就是我们的满足要求
(具体操作如下)
#include <cstdio>#include <algorithm>using namespace std;#define MAX 100005int N,C,F;struct Cow{ int s,fa; bool operator <(const Cow &c)const { return s < c.s; }} cow[MAX];int right[MAX],left[MAX],left_sum,right_sum;void heap(int a[],int n,int m) //最小堆{ int t; while(m*2 <= n) { m *= 2; if(m+1 <= n && a[m] < a[m+1]) m ++; if(a[m] > a[m/2]) { t = a[m/2]; a[m/2] = a[m]; a[m] = t; } else break; }}void make_heap(int a[],int n){ for(int i = n/2; i > 0; i --) heap(a,n,i);}int main(){ while(~scanf("%d%d%d",&N,&C,&F)) { for(int i = 1; i <= C; i ++) scanf("%d%d",&cow[i].s,&cow[i].fa);//按分数排序 sort(cow+1,cow+C+1);//先构造左边和右边的 N/2 个数// 这里注意i 和 j 表示是左右边的牛, 但是我们对于这N/2个数存放left、right都是从下标为1开始,才能维护堆left_sum = right_sum = 0; for(int i = 1,j = C-N/2+1; i <= N/2; i ++,j ++) { left[i] = cow[i].fa; left_sum += left[i]; right[i] = cow[j].fa; right_sum += right[i]; } make_heap(left,N/2); //先把左边建堆//因为一开始我们是从C-N/2 这个位置开始往左边枚举,那么对于这个之前我们要预处理一下// left[i] 表示枚举i这头牛时,之前的最小的 N/2 个数之和 for(int i = N/2+1; i <= C-N/2; i ++) { left[i] = left_sum; //首先这个left值就是 前面的left_sum//如果这头牛比之前建堆的 N/2头牛的最大要小,就更新堆,为下一头牛的left_sum准备 if(cow[i].fa < left[1]) {// 把最大牛减掉 加上新加入的牛left_sum = left_sum - left[1] + cow[i].fa; left[1] = cow[i].fa;//更新 调整 heap(left,N/2,1); } } make_heap(right,N/2); int ans = -1; for(int i = C-N/2; i > N/2; i --) //开始枚举 { if(right_sum+left[i]+cow[i].fa <= F) { ans=cow[i].s; break;}//这头牛满足 //如果上面不满足,那么就要往左边移,那么对于当前这头牛就要放到右边的堆当中去 if(cow[i].fa < right[1]) { right_sum = right_sum-right[1]+cow[i].fa; right[1]=cow[i].fa; heap(right,N/2,1); } } printf("%d\n",ans); } return 0;}
poj3481
题意:银行处理系统,每一个顾客有一个标记,还有一个优先级,对于操作1,就是添加一个顾客,操作2,服务优先级高的顾客,操作3 服务优先级低的顾客
分析,分维护一个最大堆,和一个最小堆,处理相对于的服务的时候,比如 操作2,我们在最大堆中删除,并且将次顾客标记处理啦,那么对于后面操作3处理过程中如果也是那个顾客,就可以判断是否标记,标记了就先删除,再处理下一个
//1760K 204MS#include <stdio.h>#include <string.h>#define MAX 1000005struct node{ int k,p;};node h[MAX],l[MAX]; //最大最小堆int n1,n2; //两个堆的人数bool flag[MAX]; //标记void push1(int k,int p)/{ h[++n1].k = k; h[n1].p = p; int i = n1; while(i>1 && h[i/2].p<p) { h[i].k = h[i/2].k; h[i].p = h[i/2].p; i /= 2; } h[i].k = k; h[i].p = p;}void push2(int k,int p){ l[++n2].k = k; l[n2].p = p; int i = n2; while(i>1 && l[i/2].p>p) { l[i].k = l[i/2].k; l[i].p = l[i/2].p; i /= 2; } l[i].k = k; l[i].p = p;}void heap1(int m){ int k,p; while(m*2 <= n1) { m*=2; if(m+1<=n1 && h[m].p<h[m+1].p) m++; if(h[m].p>h[m/2].p) { k = h[m].k; p = h[m].p; h[m].k = h[m/2].k; h[m].p = h[m/2].p; h[m/2].k = k; h[m/2].p = p; } else break; }}int get1(){ while(n1>0 && flag[h[1].k]) { h[1].k = h[n1].k; h[1].p = h[n1--].p; heap1(1); } if(n1 == 0) return 0; else { flag[h[1].k] = 1; return h[1].k; }}void heap2(int m){ int k,p; while(m*2 <= n2) { m*=2; if(m+1<=n2 && l[m].p>l[m+1].p) m++; if(l[m].p<l[m/2].p) { k = l[m].k; p = l[m].p; l[m].k = l[m/2].k; l[m].p = l[m/2].p; l[m/2].k = k; l[m/2].p = p; } else break; }}int get2(){ while(n2>0 && flag[l[1].k]) { l[1].k = l[n2].k; l[1].p = l[n2--].p; heap2(1); } if(n2 == 0) return 0; else { flag[l[1].k] = 1; return l[1].k; }}int main(){ memset(flag,false,sizeof(flag)); int a,k,p; n1=n2=0; while(~scanf("%d",&a)) { if(!a) continue; if(a == 1) { scanf("%d%d",&k,&p); flag[k] = 0; push1(k,p);push2(k,p); } else if(a == 2) { printf("%d\n",get1()); } else { printf("%d\n",get2()); } } return 0;}
个人愚昧观点,欢迎指正与讨论
2 0
- 二叉堆例题解题报告代码--poj3253、poj2442、poj2010、poj3481
- 二叉堆模板小结-附上解题报告poj3253、poj2442、poj2010、poj3481
- poj2010解题报告(堆)
- 【POJ2442】Sequence 解题报告+代码
- POJ3253解题报告
- poj3253解题报告c语言
- poj2442 堆
- poj2442(堆)
- POJ2442 堆
- c语言二叉堆《学习记录》poj3253
- 堆--poj3253
- [2014.3.30]poj3253 Fence Repair 解题报告(C++)
- POJ2442 Sequence 最大堆
- poj2442 Sequence----堆复习
- poj2442 Sequence(堆)
- POJ3253 Fence Repair (二叉堆 | 优先队列 | huffman树 )
- POJ2442——Squence(二叉堆+动态规划 | 滚动数组)
- Sequence Poj2442 (堆/优先队列)
- Histogram Matching
- C语言总结之条件编译
- 【转】mac os 平台下载并编译android2.3.3源码
- android开发环境搭建
- java反射详解
- 二叉堆例题解题报告代码--poj3253、poj2442、poj2010、poj3481
- 引擎相关
- 如何提高FPGA的运行速度
- 【转】在MAC系统中编译ANDROID源码与模拟器内核GoldFish
- 二叉堆模板小结-附上解题报告poj3253、poj2442、poj2010、poj3481
- grunt搭建静态服务器(简陋版)
- 文档类型: <!DOCTYPE 根元素 可用性 公共标识符 DTD-URI>
- Mybatis代码自动生成工具和插件
- 黑马程序员—TCP-客户端并发登录小例子