P3049 [USACO]园林绿化

绿园林绿化


Descriptionmathcal{Description}
有n块土地,每块有A[i]泥土,现把其改造成B[i]泥土,有3种操作:
(1)花费X向任意土地增加1泥土;
(2)花费Y向任意土地减少1泥土;
(3)花费Z*|i-j|把土地i的1泥土运到土地j。问最小花费是多少。

A[i],B[i]<=100,n<=100,X,Y,Z<=1000A[i],B[i]<=100,\n<=100,\X,Y,Z<=1000


Solution1mathcal{Solution_1}

最初想法
思考发现, 最开始土地分为两种类型 : 要求降低, 要求升高.
在两个不同类型的土地 i,ji,j 之间, 若 X+Y>ZijX+Y>Z*|i-j| 时, 则将泥土从 ii 搬往 jj 一定优于 直接升高降低.
于是按照此方法 贪心, 得到 50pts50pts.


正解部分
大概思想如上, 是因为我维护方法不对才拿了 50pts50pts, 重点看实现部分.


实现部分
对两种类型的土地分别建立两个 大根堆 Q1, Q2Q_1, Q_2, 内部元素是 单位泥土,
(可以理解为 Q1Q_1 是囤积的泥土, 可以堆到其他土地上; Q2Q_2 是筐, 可以将其他土地上的泥土倒到对应土地上),

从左往右边扫, 设当前位置为 ii, 土地类型为 要求下降, 即可以将当前泥土堆到其他土地上.
将该地泥土分为 A[i]A[i] 个单位泥土, 对每个单位泥土 单独处理,

对当前 要降低 的单位泥土, 有两种选择:

  1. 直接扔泥土, cost=Xcost=X, 此时需要 Q1.push(iZ+X)Q_1.push(i*Z + X)
  2. 从前方不同类型的土地 搬泥土, cost2=iZQ2.top.firstcost_2 = i*Z-Q_2.top.first,
  3. 从后方不同类型的土地 搬泥土,此时需要 Q2.push(iZ+cost2) Q_2.push(i*Z+cost_2)

注意以上都需执行 Ans+=min(cost,cost2)Ans += min(cost,cost_2)., (弹出操作已省略).

时间复杂度 O(N10log(N10))O(N*10*log(N*10))
Solution2mathcal{Solution_2}

可以使用 DpDp,
F[i,j]F[i, j] 表示 处理了 ii 个第一类型的单位泥土, jj 个第二类型的单位泥土 所花费的最小价值,

F[i,j]=min{F[i1,j]+XF[i,j1]+YF[i1,j1]+ZposiposjF[i, j]= minegin{cases} F[i-1, j] + X\ F[i, j-1] + Y\ F[i-1,j-1]+Z*∣pos_i-pos_j∣ end{cases}

时间复杂度 O((N10)2)O((N*10)^2)


Codemathcal{Code}
贪心代码.

#include<bits/stdc++.h>
#define reg register

const int maxn = 105;
const int inf = 0x7f7f7f7f;

int N;
int X;
int Y;
int Z;
int Ans;
int A[maxn];
int B[maxn];

std::priority_queue <int> Q1;
std::priority_queue <int> Q2;

void Work_1(int i){  // In, Up
        int cost = inf;
        if(!Q1.empty()){
                int t = Q1.top();
                int tmp = i*Z - t;
                if(tmp < X) Q1.pop(), cost = tmp;
        }
        if(cost == inf) cost = X;
        Q2.push(i*Z + cost); Ans += cost;
}

void Work_2(int i){ // Out, Down
        int cost = inf;
        if(!Q2.empty()){
                int t = Q2.top();
                int tmp = i*Z - t;
                if(tmp < Y) Q2.pop(), cost = tmp;
        }
        if(cost == inf) cost = Y;
        Q1.push(i*Z + cost); Ans += cost;
}

int main(){
        scanf("%d%d%d%d", &N, &X, &Y, &Z);
        for(reg int i = 1; i <= N; i ++) scanf("%d%d", &A[i], &B[i]);
        for(reg int i = 1; i <= N; i ++)
                for(reg int j = 1; j <= abs(B[i]-A[i]); j ++)
                        if(A[i] < B[i]) Work_1(i); 
                        else Work_2(i);
        printf("%d
", Ans);
        return 0;
}
原文地址:https://www.cnblogs.com/zbr162/p/11822592.html