zoukankan      html  css  js  c++  java
  • BZOJ 1150: [CTSC2007]数据备份Backup 优先队列+贪心+链表

    题解:我们先得到两个楼之间的距离,D[i]表示第i栋楼和第i+1栋楼之间的距离,我们要选出最小的k个数,然后就有两种情况

    1.选择了D[i],那么D[i-1]和D[i+1]都不能选择了
    2.选择了D[i+1]和D[i-1],然后无法选择D[i].

    既要么选D[i]不选D[i-1]和D[i+1],要么选D[i-1]和D[i+1]不选D[i];(怎么证明的也搞不太清楚)我们用优先队列来得到每次最小的距离,

    我们发现在选取一个数之后,只对左右两边的数有影响,选了D[i]后,我们把D[i-1]+D[i+1]-D[i]加入队列,同时D[i-1]和D[i+1]不能再选了,我们就把D[i]旁边的边删除,然后再打上标记

    和双链表中的删除一个节点类似,这里用数组代替了链表。

    还有由于我的优先队列里放的是整个结构体,所以每次取出堆顶后,L和R一定要使用数组中的,而不能直接使用当前取出的节点的L和R(这个地方wa了好几次),因为有些楼的左右节点变了,而优先队列中的还没变。

    #include<bits/stdc++.h>
    using namespace std;
    const int inf = 0x3f3f3f3f;
    const int maxn = 2e5 + 5;
    //数组代替链表 每个节点代表一栋楼的信息,以及左边,右边的楼的编号
    struct node{  
        int pos, dis, Lpos, Rpos; 
        node(int pos = 0, int dis = 0, int Lpos = 0, int Rpos = 0){ pos = pos, dis = dis, Lpos = Lpos, Rpos = Rpos; }
        bool operator<(const node &other)const{
            return dis > other.dis; 
        }
    }a[maxn];
    bool vis[maxn];
    int b[maxn],n,k;
    priority_queue<node> que;
    long long ans;
    void solve()
    {
        while (k--)
        {
            while (1)
            {
                node cur = que.top();
                que.pop();
                if (vis[cur.pos]) continue;
                int pos = cur.pos, Lpos = a[pos].Lpos, Rpos = a[pos].Rpos;   //这边这个结构体的左右节点已保存,所以下面的修改顺序没影响 /*优先队列中放整个结构体的一定要注意这个地方,这里Lpos和Rpos一定要用
                数组中的L,R,而不能直接使用cur.Lpos,cur.Rpos 我在这里卡了好长时间*/
                vis[Lpos] = vis[Rpos] = true; //这个楼已使用,那么它旁边的楼就不能再使用,打上标记,pos这个位置还会继续使用,因此pos不打标记
                ans += 1LL*cur.dis;
                a[pos].dis = a[Lpos].dis + a[Rpos].dis - a[pos].dis;// pos位置继续使用,但改变距离
                a[pos].Lpos = a[Lpos].Lpos; 
            a[pos].Rpos = a[Rpos].Rpos; a[a[Rpos].Rpos].Lpos = pos;
             a[a[Lpos].Lpos].Rpos = pos; //改变左右相邻的楼 //这4个修改顺序无影响,左右节点已保存
    que.push(a[pos]); break; } } } int main() { cin >> n >> k; for (int i = 1; i <= n; i++) { cin >> b[i]; } for (int i = 1; i < n; i++) { a[i].dis = b[i + 1] - b[i]; a[i].pos = i; a[i].Lpos = i - 1; a[i].Rpos = i + 1; que.push(a[i]); } a[n - 1].Rpos = 0; a[0].dis = a[n].dis = inf; solve(); cout << ans; return 0; }

    再来一个不放结构体的

    struct cmp{
        bool operator()(int a, int b)
        {
            return D[a] > D[b];
        }
    };
    priority_queue<int, vector<int>, cmp>;

     洛谷P1484 种树 和这题类似,选出不超过k个节点,使值最大。

  • 相关阅读:
    join命令
    参与者模式
    字符串中的第一个唯一字符
    Git与SVN对比
    惰性模式
    .NET Conf 2020
    使用Github部署Azure应用服务
    Azure Terraform(一)入门简介
    打日志还能打出个线上Bug_ 太难了。。。
    让API并行调用变得如丝般顺滑的绝招
  • 原文地址:https://www.cnblogs.com/xiaoguapi/p/10360143.html
Copyright © 2011-2022 走看看