3道经典的优先队列题
优先队列是一种十分强大的数据结构,它保持了一种动态的有序性,对于不断改变有入队的操作,而又需要某种最大或最小的操作的问题是再合适不过了,通常优先队列的实现是由最小堆或者最大堆完成的,并通过堆排序保持队列的有序性,模拟队列的结构,在实际比赛中要写一个堆排序还是要一定的时间的,但是stl中queue容器中已经可以实现优先队列,下面以三道基本的题目来演示priority_queue的作用。聪明的
·
优先队列是一种十分强大的数据结构,它保持了一种动态的有序性,对于不断改变有入队的操作,而又需要某种最大或最小的操作的问题是再合适不过了,通常优先队列的实现是由最小堆或者最大堆完成的,并通过堆排序保持队列的有序性,模拟队列的结构,在实际比赛中要写一个堆排序还是要一定的时间的,但是stl中queue容器中已经可以实现优先队列,下面以三道基本的题目来演示priority_queue的作用。
聪明的木匠
Time Limit: 1000ms, Special Time Limit: 2500ms, Memory Limit: 32768KB
Total submit users: 23, Accepted users: 10
Problem 10611 : No special judgement
Problem description
最近,一位老木匠遇到了一件非常棘手的问题。他需要将一根非常长的木棒切成N 段。每段的长度分别为 L1 ,L2 ,…,LN ( 1≤L1 ,L2 ,…,LN ≤1000 ,且均为整数)个长度单位。 ∑Li (i=1,2,…,N) 恰好就是原木棒的长度。我们认为切割时仅在整数点处切且没有木材损失。
木匠发现,每一次切割花费的体力与该木棒的长度成正比,不妨设切割长度为 1 的木棒花费 1 单位体力。例如,若 N=3 , L1 =3,L2 =4,L3 =5 ,则木棒原长为 12 ,木匠可以有多种切法,如:先将 12 切成 3+9. ,花费 12 体力,再将 9 切成 4+5 ,花费 9 体力,一共花费 21 体力;还可以先将 12 切成 4+8 ,花费 12 体力,再将 8 切成 3+5 ,花费 8 体力,一共花费 20 体力。显然,后者比前者更省体力。
那么,木匠至少要花费多少体力才能完成切割任务呢?
Input
输入数据的第一行为一个整数N(2≤N≤150,000) ;
在接下来的 N 行中,每行为一个整数 Li (1≤Li ≤1000) 。
Output
输出数据仅有一行,为一个整数,表示木匠最少要花费的体力。测试数据保证这个整数不大于231 -1 。
Sample Input
4
3
5
7
11
Sample Output
49
Problem Source
2010年河北大学程序设计竞赛
最优的方法是每次切出最小的合并,显然要使用优先队列;
[cpp:firstline[1]] view plaincopyprint?#include <iostream>
#include <queue>
struct cmp
{
bool operator ()(const int &i,const int &j)
{
return i>j;
}
};
using namespace std;
int main()
{
priority_queue<int,vector<int>,cmp> s;
int n;
while(cin>>n)
{
for(int i=0;i<n;i++)
{
int key;
scanf("%d",&key);
s.push(key);
}
int sum=0;
while(n>=2)
{
int a,b;
a=s.top();
s.pop();
b=s.top();
s.pop();
s.push(a+b);
//cout<<a<<' '<<b;
sum+=a+b;
n--;
}
cout<<sum<<endl;
}
return 0;
}
#include <iostream>
#include <queue>
struct cmp
{
bool operator ()(const int &i,const int &j)
{
return i>j;
}
};
using namespace std;
int main()
{
priority_queue<int,vector<int>,cmp> s;
int n;
while(cin>>n)
{
for(int i=0;i<n;i++)
{
int key;
scanf("%d",&key);
s.push(key);
}
int sum=0;
while(n>=2)
{
int a,b;
a=s.top();
s.pop();
b=s.top();
s.pop();
s.push(a+b);
//cout<<a<<' '<<b;
sum+=a+b;
n--;
}
cout<<sum<<endl;
}
return 0;
}
【问题描述】
在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过n-1次合并之后,就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。
因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为1,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。
例如有3种果子,数目依次为1,2,9。可以先将 1、2堆合并,新堆数目为3,耗费体力为3。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为12,耗费体力为 12。所以多多总共耗费体力=3+12=15。可以证明15为最小的体力耗费值。
【输入文件】
输入文件fruit.in包括两行,第一行是一个整数n(1 <= n <= 10000),表示果子的种类数。第二行包含n个整数,用空格分隔,第i个整数ai(1 <= ai <= 20000)是第i种果子的数目。
【输出文件】
输出文件fruit.out包括一行,这一行只包含一个整数,也就是最小的体力耗费值。输入数据保证这个值小于231。
【样例输入】
3
1 2 9
【样例输出】
15
【数据规模】
对于30%的数据,保证有n <= 1000;
对于50%的数据,保证有n <= 5000;
对于全部的数据,保证有n <= 10000。
合并的最优方法是合并最小的两堆,通过优先队列就可以轻松实现;
[cpp:firstline[1]] view plaincopyprint?#include <iostream>
#include <queue>
struct cmp
{
bool operator ()(const int &i,const int &j)
{
return i>j;
}
};
using namespace std;
int main()
{
priority_queue<int,vector<int>,cmp> s;
int n;
while(cin>>n)
{
for(int i=0;i<n;i++)
{
int key;
scanf("%d",&key);
s.push(key);
}
int sum=0;
while(n>=2)
{
int a,b;
a=s.top();
s.pop();
b=s.top();
s.pop();
s.push(a+b);
//cout<<a<<' '<<b;
sum+=a+b;
n--;
}
cout<<sum<<endl;
}
return 0;
}
#include <iostream>
#include <queue>
struct cmp
{
bool operator ()(const int &i,const int &j)
{
return i>j;
}
};
using namespace std;
int main()
{
priority_queue<int,vector<int>,cmp> s;
int n;
while(cin>>n)
{
for(int i=0;i<n;i++)
{
int key;
scanf("%d",&key);
s.push(key);
}
int sum=0;
while(n>=2)
{
int a,b;
a=s.top();
s.pop();
b=s.top();
s.pop();
s.push(a+b);
//cout<<a<<' '<<b;
sum+=a+b;
n--;
}
cout<<sum<<endl;
}
return 0;
}
删除最小值
Time Limit: 1000ms, Special Time Limit: 2500ms, Memory Limit: 32768KB
Total submit users: 8, Accepted users: 8
Problem 10604 : No special judgement
Problem description
序列A 中有 N 个元素,序列 B 中也有 N 个元素,依次将序列 B 中的元素移进序列 A ,对于每次移进元素,首先在一行输出序列 A 中的最小值,然后在 A 在加入该元素,接着在序列 B 中删除该元素,接着在序列 A 中删除刚才输出的最小值。
Input
共三行,第一行给出元素数目N ,第二行给出 A 中的原始 N 个元素,第三行给出 B 中的原始 N 个元素。 1 ≤ n ≤ 10000 ,每个元素值范围为 [0 , 100000] 。
Output
在每次将B中的元素移入A之前,在一行里输出A中所有元素的最小值。
Sample Input
3
3 9 6
5 2 10
Sample Output
3
5
2
这道题目跟到模拟题目差不多……
[cpp:firstline[1]] view plaincopyprint?#include <iostream>
#include <queue>
struct cmp
{
bool operator ()(const int &i,const int &j)
{
return i>j;
}
};
using namespace std;
int main()
{
int b[10003];
priority_queue<int,vector<int>,cmp> s;
int n;
while(cin>>n)
{
for(int i=0;i<n;i++)
{
int key;
scanf("%d",&key);
s.push(key);
}
for(int i=0;i<n;i++)
{
scanf("%d",&b[i]);
}
for(int j=0;j<n;j++)
{
//cout<<b[j]<<endl;
printf("%d/n",s.top());
s.pop();
s.push(b[j]);
}
}
return 0;
}
#include <iostream>
#include <queue>
struct cmp
{
bool operator ()(const int &i,const int &j)
{
return i>j;
}
};
using namespace std;
int main()
{
int b[10003];
priority_queue<int,vector<int>,cmp> s;
int n;
while(cin>>n)
{
for(int i=0;i<n;i++)
{
int key;
scanf("%d",&key);
s.push(key);
}
for(int i=0;i<n;i++)
{
scanf("%d",&b[i]);
}
for(int j=0;j<n;j++)
{
//cout<<b[j]<<endl;
printf("%d/n",s.top());
s.pop();
s.push(b[j]);
}
}
return 0;
}
以上三道题目如果掌握优先队列再去解答十分简单,做这种优先队列的题目,如果发现是使用优先队列的就很简单了(说的这都是废话!)
stl中的优先队列的模板:
#include <queue>
priority_queue <int> q;
这是按照从大到小的队列;
#include <queue>
struct cmp
{
bool operator ()(const int &i,const int &j)
{
return i>j;
}
};
priority_queue <int> q;
这是从小到大的优先队列;
更多推荐
已为社区贡献1条内容
所有评论(0)