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 }

 

 

posted @ 2014-03-01 22:00  再见~雨泉  阅读(394)  评论(0编辑  收藏  举报