BZOJ 2151 2151: 种树 (贪心+堆)

Posted konjak魔芋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 2151 2151: 种树 (贪心+堆)相关的知识,希望对你有一定的参考价值。

2151: 种树

Description

A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树。园林部门得到指令后,初步规划出n个种树的位置,顺时针编号1到n。并且每个位置都有一个美观度Ai,如果在这里种树就可以得到这Ai的美观度。但由于A城市土壤肥力欠佳,两棵树决不能种在相邻的位置(i号位置和i+1号位置叫相邻位置。值得注意的是1号和n号也算相邻位置!)。最终市政府给园林部门提供了m棵树苗并要求全部种上,请你帮忙设计种树方案使得美观度总和最大。如果无法将m棵树苗全部种上,给出无解信息。

Input

输入的第一行包含两个正整数n、m。第二行n个整数Ai。

Output

输出一个整数,表示最佳植树方案可以得到的美观度。如果无解输出“Error!”,不包含引号。

Sample Input

【样例输入1】
7 3
1 2 3 4 5 6 7
【样例输入2】
7 4
1 2 3 4 5 6 7

Sample Output

【样例输出1】
15

【样例输出2】
Error!
【数据规模】
对于全部数据:m<=n;
-1000<=Ai<=1000
N的大小对于不同数据有所不同:
数据编号 N的大小 数据编号 N的大小
1 30 11 200
2 35 12 2007
3 40 13 2008
4 45 14 2009
5 50 15 2010
6 55 16 2011
7 60 17 2012
8 65 18 199999
9 200 19 199999
10 200 20 200000

HINT

Source

 

 

【分析】

  应该是一种很经典的贪心吧【为什么我不会。。。

  贪心思想:每次选择合法的最大的一个

  如果这是这样当然是错的,要给他一点后悔的机会【感觉有点网络流的思想啊

  假设你选的最大的一个是x2,x1、x3和他相邻,其实可能你的最优方案是不选x2,而选x1、x3【但是一定两个都选,不可能只选x1或x3,因为x2最大

  所以我们把x1 x2 x3 都删掉,插入一个新结点,贡献为x1+x3-x2,如果选了他,说明你反悔了,决定选x1、x3而放弃x2。

  【思路就是这么巧妙简单啊~~

 

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<cmath>
 7 #include<queue>
 8 #include<vector>
 9 using namespace std;
10 #define Maxn 200010
11 
12 struct node
13 {
14     int x,id;
15     friend bool operator < (node x,node y)
16     {
17         return x.x<y.x;
18     }
19 };
20 
21 priority_queue<node > q;
22 
23 bool mark[2*Maxn];
24 int lt[2*Maxn],nt[2*Maxn],w[2*Maxn];
25 
26 int main()
27 {
28     int n,m;
29     scanf("%d%d",&n,&m);
30     for(int i=0;i<n;i++) scanf("%d",&w[i]);
31     
32     if(m>n/2) printf("Error!\\n");
33     else
34     {
35         int ans=0,cnt=n-1;
36         while(!q.empty()) q.pop();
37         for(int i=0;i<n;i++)
38         {
39             node nw;
40             nw.x=w[i];nw.id=i;
41             q.push(nw);
42         }
43         for(int i=0;i<n;i++) nt[i]=(i+1)%n;
44         for(int i=0;i<n;i++) lt[i]=(i-1+n)%n;
45         memset(mark,0,sizeof(mark));
46         for(int i=1;i<=m;i++)
47         {
48             while(mark[q.top().id]) q.pop();
49             node nw=q.top();q.pop();
50             ans+=nw.x;
51             cnt++;
52             mark[lt[nw.id]]=mark[nt[nw.id]]=1;
53             nt[lt[lt[nw.id]]]=cnt;lt[nt[nt[nw.id]]]=cnt;
54             nt[cnt]=nt[nt[nw.id]];lt[cnt]=lt[lt[nw.id]];
55             node xx;
56             w[cnt]=w[lt[nw.id]]+w[nt[nw.id]]-nw.x;
57             xx.x=w[cnt];xx.id=cnt;
58             q.push(xx);
59         }
60         printf("%d\\n",ans);
61     }
62     return 0;
63 }
View Code

 

2017-01-13 20:32:36

以上是关于BZOJ 2151 2151: 种树 (贪心+堆)的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 2151: 种树贪心+堆

BZOJ2151 种树 [贪心+链表]

BZOJ 2151 种树(可反悔贪心,链表)BZOJ千题计划就图一乐

BZOJ 2151 种树(可反悔贪心,链表)BZOJ千题计划就图一乐

bzoj2151种树(堆/优先队列+双向链表)

bzoj2151: 种树(双向链表+堆)