zoukankan      html  css  js  c++  java
  • BZOJ2151 种树 [贪心+链表]

    Description

    A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树。

    园林部门得到指令后,初步规划出n个种树的位置,顺时针编号1到n。并且每个位置都有一个美观度Ai,如果在这里种树就可以得到这Ai的美观度。但由于A城市土壤肥力欠佳,两棵树决不能种在相邻的位置(i号位置和i+1号位置叫相邻位置。值得注意的是1号和n号也算相邻位置!)。

    最终市政府给园林部门提供了m棵树苗并要求全部种上,请你帮忙设计种树方案使得美观度总和最大。如果无法将m棵树苗全部种上,给出无解信息。

    Input

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

    Output

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

    Sample Input

    7 3

    1 2 3 4 5 6 7

    Sample Output

    15

    Hint

    对于全部数据:m<=n; -1000<=Ai<=1000; n<=200000;

    思路

    这道题目看上去很容易想到是DP。实际上却是一种神贪心。。。都是套路

    每次贪心选取最大值,答案加上这个最大值,最大值左右两边当然不能再选,于是就标记为访问过。最大值不难想到我们可以用堆进行维护。

    但是这个贪心显然是不完善的。当最大值左右两边之和大于它本身时,就会产生错误。于是就有一种神奇的操作:将左右两边之和减去最大值,作为新的节点,覆盖掉原来的最大值,并删去左右两个节点。

    原因是要么选最大值,要么选它的左右之和,选最大值时答案加上这个最大值,不再去选新的节点,选左右之和时答案还是加上最大值,只不过后面还要加上新节点的值。也就是当我们再次选取的新节点时,也就相当于选取当时最大值的左右之和,而没有选最大值。

    这个神奇的操作有删除左右节点的过程,因此我们要用双向链表进行维护。总的来说这个思路比较难想到,但是代码还是比较好打的。

    代码

    需要注意的细节:
    1.链表时环状的,第一个节点与最后一个相邻
    2.进行删除节点时要注意前驱和后继都要修改
    3.操作的顺序要注意,先更新值再进行删除

    #include <bits/stdc++.h>
    #define MAXN 200005
    
    int n, m, ans, num[MAXN], pre[MAXN], next[MAXN];
    bool vis[MAXN];
    
    struct node
    {
    	int v, p;
    	bool operator < (const node &x) const
    	{
    		return v<x.v;
    	}
    }; 
    std::priority_queue <node> q;  //STL优先队列,建立大根堆
    
    int main()
    {
    	scanf("%d%d",&n,&m);
    	if(m*2>n) {printf("Error!
    "); return 0;}  //特判无解情况
    	for(int i=1; i<=n; i++)
    	{
    		scanf("%d",&num[i]);
    		q.push((node){num[i], i});
    		pre[i]=i-1; next[i]=i+1;  //数组模拟链表
    	}
    	pre[1]=n; next[n]=1; 
    	for(int i=1; i<=m; i++)
    	{
    		while(vis[q.top().p]) q.pop();  //访问过的直接出队
    		node top=q.top(); q.pop();
    		ans+=top.v;
    		vis[next[top.p]]=vis[pre[top.p]]=1;  //将左右节点标记为访问过的
    		num[top.p]=num[pre[top.p]]+num[next[top.p]]-num[top.p]; 
    		//删除左右节点
    		pre[top.p]=pre[pre[top.p]];
    		next[top.p]=next[next[top.p]];
    		next[pre[top.p]]=top.p;
    		pre[next[top.p]]=top.p;
    		q.push((node){num[top.p], top.p});
    	}
    	printf("%d
    ",ans);
    } 
    
  • 相关阅读:
    mysql的数据类型和字段属性
    随便弄个名字 以后改
    drupal 不错的网址
    iwebshop 模板手册
    1.nginx 防注入
    DenyHosts 安装及配置详解
    drupal8 管理入门
    1.php代码块
    Drupal Nginx伪静态设置方法
    Nginx优化(十七)
  • 原文地址:https://www.cnblogs.com/CrazyDave/p/8504166.html
Copyright © 2011-2022 走看看