一個關鍵之處在於狀態轉移的理解。
考慮已經按照電壓升序排好序的bulb,假若有a, b, c, d, e那麼若是有一些燈泡升級爲了e,那麼這些燈泡序號必定是連續的,例如b, c燈泡升級爲e,但是d 沒有,這種「跳躍」的狀況是不可能的。緣由以下:
假設這種狀況可能,那麼上面這個例子中,隔在中間一定有一個沒有升級的,在這裏是d,顯然d不肯意升級爲e的緣由只能是d的單價比e要貴(否則的話,所有轉化爲e,還能省掉電源錢,這樣更划算),那那些升級爲e的b, c還不如升級成d, 這樣成本反而更低,因此可見,這種狀態轉移必定不是產生最優解的狀態轉移。ios
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <queue> #include <cmath> #include <vector> using namespace std; const int maxn= 1005; const int INF= 0x3f3f3f3f; struct bulb { int v, k, c, l; bulb()=default; bulb(int vv, int kk, int cc, int ll) : v(vv), k(kk), c(cc), l(ll) {} bool operator < (const bulb & b) const { return this->v < b.v; } }ls[maxn]; int s[maxn], dp[maxn]; void Init(int n) { s[0]= 0; memset(dp, 0x3f, sizeof(dp)); dp[0]= 0; for (int i= 1; i<= n; ++i){ s[i]= s[i-1]+ls[i].l; } } int main() { int n; int v, k, c, l; while (1== scanf("%d", &n) && n){ for (int i= 1; i<= n; ++i){ scanf("%d %d %d %d", &v, &k, &c, &l); ls[i]= bulb(v, k, c, l); } sort(ls+1, ls+n+1); Init(n); for (int i= 1; i<= n; ++i){ int &x= dp[i]; c= ls[i].c; for (int j= i-1; j>= 0; --j){ x= min(x, dp[j]+(s[i]-s[j])*c); } x+= ls[i].k; } printf("%d\n", dp[n]); } return 0; }