1. 程式人生 > >洛谷 P3049 Landscaping ( 貪心 || DP)

洛谷 P3049 Landscaping ( 貪心 || DP)

cor turn name line while bits ide spa con

題意 : 有n塊土地,每塊有A[i]泥土,現把其改造成B[i]泥土,有3種操作:(1)花費X向任意土地增加1泥土;(2)花費Y向任意土地減少1泥土;(3)花費Z*|i-j|把土地i的1泥土運到土地j。問最小花費是多少。

分析 :

參考了洛谷大神們給出的思路,下面簡述一下

簡單的講就是對於每一個點,先將其花費一定的價值使得其數量

變成 B[i] 泥土,但是這個花費不一定是最優的,可以通過後期調整

來達到使得花費更小,調整的方案當然就是對於改變前後缺少和

改變前後增加這兩種土地來進行考慮,對於缺少的土地,可以考慮

直接花費 X 的代價去買土地,也可以考慮從先前改變前後增加的土

地花費 Z 轉移過來。對於改變前後增加的土地,也是差不多的情況

先定義 opt(x) 代表當前點暫時的最優取值,即最小花費

舉個例子,若當前第一個點是改變前後缺少的,那麽由於還沒有枚舉到

改變前後增加的點,所以只能通過花費 X 的方案來使得其改變前後相等

即 opt(first_point) = (B[first_point] - A[first_point])*X ==> 當然,這只是暫時的

for( 按照下標從小到到大枚舉每一個點 ) :

  若當前改變前後的土地差值不變 continue

  若當前改變前後土地是缺少的 :

    假設當前點是 j ,且之前有 i1、i2、i3…… 是改變前後增加的

    若選擇通過從從這些 i 來轉移到 j 使得改變前後相等

    則有 (j-i1)*Z - opt(i1)、(j-i2)*Z - opt(i2)、(j-i3)*Z - opt(i3)…… 當然要從這些取最小

    考慮一下為什麽是樣子,因為是從 i 轉移而來,所以之前 i 產生的最優花費,我們應當是要減掉的

    以此來抵消掉之前 i 的花費,使得其轉移到 j 這裏來,產生更加優秀的方案,不理解就往下看

    簡化一下有 j*Z - max[i + opt(i)] ==> 從那麽多個 i 中取最大的,才能保證花費最小

    故最後 opt(j) = min( X, j*Z - max[i + opt(i)] ) ==> 當然還要和直接購買這種方案取一個 min

  若改變前後土地是增加的 :

    和缺少的情況很像,就不闡述了

   ans += opt(j)

上面就是 偽代碼思路 這個貪心顯而易見是正確的,不斷從多種方式取最優

這種貪心思路很容易想到,就是不知道怎麽去用代碼寫出來,或者沒有一個清晰的思路

這種先確定一個值,後面再去調整取更優的貪心思路,學習一下

至於DP的思路,其實我沒看過,有空再說

技術分享圖片
#include<bits/stdc++.h>
#define LL long long
using namespace std;
LL N, X, Y, Z;
priority_queue<LL> opt_lack;///表示每一個缺少點的最優取值
priority_queue<LL> opt_surplus;///表示每一個多余點的最優取值

int main(void)
{
    while(~scanf("%lld %lld %lld %lld", &N, &X, &Y, &Z)){

        while(!opt_lack.empty()) opt_lack.pop();
        while(!opt_surplus.empty()) opt_surplus.pop();

        LL before, after, ans = 0;
        for(LL j=1; j<=N; j++){
            scanf("%lld %lld", &before, &after);
            if(before == after) continue;
            if(before < after){
                for(LL i=1; i<=after-before; i++){
                    if(opt_surplus.empty() || j*Z - opt_surplus.top() >= X){
                        ans += X;
                        opt_lack.push(j*Z+X);
                    }else{
                        LL T = opt_surplus.top(); opt_surplus.pop();
                        ans += j*Z - T;
                        opt_lack.push(j*Z + j*Z - T);
                    }
                }
            }else{
                for(LL i=1; i<=before-after; i++){
                    if(opt_lack.empty() || j*Z - opt_lack.top() >= Y){
                        ans += Y;
                        opt_surplus.push(j*Z+Y);
                    }else{
                        LL T = opt_lack.top(); opt_lack.pop();
                        ans += j*Z - T;
                        opt_surplus.push(j*Z + j*Z - T);
                    }
                }
            }
        }

        printf("%lld\n", ans);
    }
    return 0;
}
View Code

洛谷 P3049 Landscaping ( 貪心 || DP)