首页 > 代码库 > 种树(贪心)
种树(贪心)
2151: 种树
Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 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
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
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 }
种树(贪心)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。