首页 > 代码库 > 种树(贪心)

种树(贪心)

2151: 种树

Time Limit: 10 Sec  Memory Limit: 259 MB
Submit: 714  Solved: 397
[Submit][Status][Discuss]

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
 
 
//看了题解,思索了很久才明白,太厉害了。。。
如果没有必须要隔一个坑种一棵树的条件的话,只许排个序一直选最大的美观值就好了,
但是有这个条件,还是每次选最大美观值的坑种,直接删除边上两个坑和自己这个坑,就可能有个问题 比如 4 5 4 这样,选了 5 ,但种边上这两点美观度更好,
所以,非常关键的思路就来了,在你选择这棵坑后,删除边上的两棵,并且把自己的值改为 4+4-5 = 3 ,成为一个新的坑,然后就可以重复进行选最大的美观度的操作了
如果你后来又选了这个再造坑,说明两边的和大于中间的,这样就能反悔了,剩下的还有一些细节的原因,想清楚并不难。
 
实现其实也比较难,建立一个二叉最大堆,每次取出最大值,并修改值,并删除边上的坑的值,在维护堆,一个循环取数,ok
//细节部分写错,wa 很多次。。。
技术分享
 1 /* *********************************************** 2 ┆  ┏┓   ┏┓ ┆ 3 ┆┏┛┻━━━┛┻┓ ┆ 4 ┆┃       ┃ ┆ 5 ┆┃   ━   ┃ ┆ 6 ┆┃ ┳┛ ┗┳ ┃ ┆ 7 ┆┃       ┃ ┆ 8 ┆┃   ┻   ┃ ┆ 9 ┆┗━┓ 马 ┏━┛ ┆10 ┆  ┃ 勒 ┃  ┆      11 ┆  ┃ 戈 ┗━━━┓ ┆12 ┆  ┃ 壁     ┣┓┆13 ┆  ┃ 的草泥马  ┏┛┆14 ┆  ┗┓┓┏━┳┓┏┛ ┆15 ┆   ┃┫┫ ┃┫┫ ┆16 ┆   ┗┻┛ ┗┻┛ ┆17 *************************************************/18 19 #include <iostream>20 #include <stdio.h>21 #include <math.h>22 using namespace std;23 24 const int inf = 21e8;25 const int maxn= 2e5+2;26 27 int a[maxn];28 int h[maxn];29 int pos[maxn];30 int l[maxn],r[maxn];31 int n,m;32 33 void up(int u)34 {35     while (u>1)36     {37         if (a[h[u]]>a[h[u/2]])38         {39             swap(h[u],h[u/2]);40             swap(pos[h[u]],pos[h[u/2]]);41             u/=2;42         }43         else break;44     }45 }46 47 void down(int x)//在堆中的排序的编号48 {49     int u;50     while (x*2<=n)51     {52         if (a[h[x*2]] > a[h[x*2+1]] || x*2==n) u=x*2;53         else u=x*2+1;54         if (a[h[x]]<a[h[u]])55         {56             swap(h[x],h[u]);57             swap(pos[h[x]],pos[h[u]]);58             x=u;59         }60         else break;61     }62 }63 64 int main()65 {66     while (scanf("%d%d",&n,&m)!=EOF)67     {68         int i;69         for (i=1;i<=n;i++)70         {71             scanf("%d",&a[i]);72             l[i]=i-1;r[i]=i+1;73             h[i]=pos[i]=i;74             up(i);75         }76         l[1]=n;r[n]=1;77         if (m>n/2)78         {79             printf("Error!\n");80             continue;81         }82         int x,ans=0;83         for (i=1;i<=m;i++)84         {85             x=h[1];86             ans+=a[x];87             a[x]=a[l[x]]+a[r[x]]-a[x];      //变为一个新的点88             a[l[x]]=-inf;down(pos[l[x]]);89             a[r[x]]=-inf;down(pos[r[x]]);90             down(1);                        //将这个新的点调整位置91             l[x]=l[l[x]];r[x]=r[r[x]]; //删除后的左右位置变化92             r[l[x]]=x;l[r[x]]=x;93         }94 95         printf("%d\n",ans);96     }97     return 0;98 }
View Code

 

 
 
 

种树(贪心)