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个节点,使值最大。

posted @ 2019-02-10 20:19  TLE自动机  阅读(134)  评论(0编辑  收藏  举报