• [BZOJ 1150] [CTSC2007] 数据备份Backup 【贪心 + 链表】


    题目链接:BZOJ - 1150

    题目分析

    可以看出,我们选的 k 条边一定是相邻两点之间的线段。我们可以将每条边看成一个点,那么我们就是要在 n-1 个点中选出互不相邻的 k 个,使它们的和最小。

    我们使用一种神奇的贪心,开始的时候将所有的点权加入堆中,然后取 k 次,每次取权值最小的点,然后将这个点的点权加入答案中,我们取了这个点之后就不能取与它相邻的两个点了,所以我们要将这个点和相邻两点的权值都从堆中删除。但是我们最终的答案并不一定要取这个点,有可能我们会不取这个点,而是取与它相邻的两个点。所以我们在删除了这个点和与它相邻的两个点之后,要在堆里加入一个新的点:权值是与这个点相邻的两个点的权值和-这个点的权值,如果之后取到这个新的点就相当于撤销取这个点,而是取与它相邻的两个点,这样取到的点数还是加一的。

    然后这样处理之后我们就认为这个新建的点取代了之前的3个点的位置,然后与这3个点两边的点相邻,需要用链表维护。

    还有特殊的情况,对于两端的点,与它们相邻的点只有1个,我们要在第一个点之前和最后一个点之后分别加上一个权值为 INF 的点,这样进行处理之后新建的点的权值也一定非常大,之后就不会被取到。

    代码

    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <set>
    
    using namespace std;
    
    const int MaxN = 100000 + 5, INF = 999999999;
    
    int n, k, Ans;
    int A[MaxN], d[MaxN], Next[MaxN], Prev[MaxN];
    
    struct ES
    {
    	int x, y;
    	ES() {}
    	ES(int a, int b) {x = a; y = b;}
    	
    	bool operator < (const ES &e) const
    	{
    		if (y == e.y) return x < e.x;
    		return y < e.y;
    	}
    };
    
    set<ES> S;
    set<ES> :: iterator It;
    
    int main()
    {
    	scanf("%d%d", &n, &k);
    	for (int i = 1; i <= n; ++i)
    	{
    		scanf("%d", &d[i]);
    		A[i] = d[i] - d[i - 1];
    	}
    	for (int i = 2; i <= n; ++i) 
    	{
    		Next[i] = i + 1;
    		Prev[i] = i - 1;
    		S.insert(ES(i, A[i]));
    	}
    	A[1] = A[n + 1] = INF;
    	int x;
    	for (int i = 1; i <= k; ++i)
    	{
    		It = S.begin();
    		x = (*It).x;
    		Ans += A[x];
    		S.erase(ES(x, A[x]));
    		S.erase(ES(Prev[x], A[Prev[x]]));
    		S.erase(ES(Next[x], A[Next[x]]));
    		A[x] = A[Prev[x]] + A[Next[x]] - A[x];
    		S.insert(ES(x, A[x]));
    		if (Prev[Prev[x]]) Next[Prev[Prev[x]]] = x;
    		if (Next[Next[x]]) Prev[Next[Next[x]]] = x;
    		Prev[x] = Prev[Prev[x]]; 
    		Next[x] = Next[Next[x]];
    	}
    	printf("%d
    ", Ans);
    	return 0;
    }
    

      

  • 相关阅读:
    《CLR via C#》读书笔记 之 基元类型、引用类型和值类型 明
    《CLR via C#》读书笔记 之 类型和成员基础 明
    《CLR via C#》读书笔记 之 方法 明
    设计模式基础(一):UML中关系图解 明
    【转载】c#类的成员初始化顺序 明
    《CLR via C#》读书笔记 之 接口 明
    《CLR via C#》读书笔记 之 事件 明
    《CLR via C#》读书笔记 之 参数 明
    三塔DP——http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3554
    二分求幂——http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3549
  • 原文地址:https://www.cnblogs.com/JoeFan/p/4622902.html
Copyright © 2020-2023  润新知