POJ3253Fence Repair(优先队列或单调队列)
http://poj.org/problem?id=3253
经典题目了,大意是说如果要切断一个长度为a的木条需要花费代价a, 问要切出要求的n个木条所需的最小代价。
无论是以下哪种方法,最原始的思路就是从相反的角度思考,将每两个合并,花费的代价是他们两个的和,一直到最后只剩下一个
方法一:
使用STL的priority_queue,先将所有的木条放入到队列中。每次取出两个木条将他们的长度相加,加入到花费当中去,然后放回到队列中。
这样计算的时间复杂度就是O(NlogN)。
方法二:
使用单调队列,我们可以分析到,由于每次取出的都是优先队列中最小的两个,也就是首部的两个,那我们可以考虑另外借用一个数组b用来存放每次取出的两个数的和,我们注意到,每次取出来的两个数相加,得到的和也是单调递增的(这个很容易证明),可以看下面的例子:
原始状态:
a 1 3 5 6 7 8 9
b null
第一次在a里取出两个数1,3相加,放入b中:
a 5 6 7 8 9
b 4
这里我们先从a、b两个数组队首取出一个最小的数4,再从两个数组的队首取出一个最小的数(此时b数组已经队空)5,相加后放入b:
a 6 7 8 9
b 9
同理,这次会取出6和7,相加放入b(注意每次相加的结果都是放入b中的,这里不放入a中是为了保证a和b数组的单调性):
a 8 9
b 9 13
经过几次操作后会得到:
a null
b 39
最后a队列空,b队列只剩下一个数,这时合并就结束了
我们可以注意到,由于每次都将相加得到的和放进了b队列,所以b一定是单调递增的, 而且最后平均每个数只被使用了一次,所以它的复杂度是O(N)的。
单调队列 和 优先队列:
1 #include <map> 2 #include <set> 3 #include <stack> 4 #include <queue> 5 #include <cmath> 6 #include <ctime> 7 #include <vector> 8 #include <cstdio> 9 #include <cctype> 10 #include <cstring> 11 #include <cstdlib> 12 #include <iostream> 13 #include <algorithm> 14 using namespace std; 15 #define INF 0x3f3f3f3f 16 #define mem0(a) memset(a,0,sizeof(a)) 17 #define mem1(a) memset(a,-1,sizeof(a)) 18 #define lson k<<1, L, mid 19 #define rson k<<1|1, mid+1, R 20 21 typedef long long LL; 22 const double eps = 1e-12; 23 const int MAXN = 100005; 24 const int MAXM = 500005; 25 26 int main() 27 { 28 int N, len; 29 while(~scanf("%d", &N)) 30 { 31 priority_queue<LL, vector<LL>, greater<LL> >q; 32 for(int i=0;i<N;i++) 33 { 34 scanf("%d", &len); 35 q.push((LL)len); 36 } 37 LL ans = 0; 38 while(q.size() > 1) 39 { 40 LL p = q.top(); q.pop(); 41 p += q.top(); q.pop(); 42 ans += p; 43 q.push(p); 44 } 45 printf("%lld\n", ans); 46 } 47 return 0; 48 }
1 #include <map> 2 #include <set> 3 #include <stack> 4 #include <queue> 5 #include <cmath> 6 #include <ctime> 7 #include <vector> 8 #include <cstdio> 9 #include <cctype> 10 #include <cstring> 11 #include <cstdlib> 12 #include <iostream> 13 #include <algorithm> 14 using namespace std; 15 #define INF 0x3f3f3f3f 16 #define mem0(a) memset(a,0,sizeof(a)) 17 #define mem1(a) memset(a,-1,sizeof(a)) 18 #define lson k<<1, L, mid 19 #define rson k<<1|1, mid+1, R 20 21 typedef long long LL; 22 const double eps = 1e-12; 23 const int MAXN = 20005; 24 const int MAXM = 500005; 25 26 LL a[MAXN], b[MAXN]; 27 28 int main() 29 { 30 int N; 31 while(~scanf("%d", &N)) 32 { 33 mem0(b); 34 for(int i=0;i<N;i++) scanf("%lld", &a[i]); 35 sort(a, a+N); 36 int frontA=0, frontB=0, rearB=0, num=0; 37 LL ans=0; 38 while(++num<N) 39 { 40 int sum = 0; 41 if(frontB==rearB || (frontA<N&&a[frontA]<b[frontB])) { sum += a[frontA]; frontA ++; } 42 else { sum += b[frontB]; frontB++; } 43 if(frontB==rearB || (frontA<N&&a[frontA]<b[frontB])) { sum += a[frontA]; frontA ++; } 44 else { sum += b[frontB]; frontB++; } 45 b[rearB++] = sum; 46 ans += sum; 47 } 48 printf("%lld\n", ans); 49 } 50 return 0; 51 }