\(n\)個任務排成乙個序列,分成若干批,執行一批任務所需的時間是啟動時間加上每個任務所需時間之和。
同一批任務將在同一時刻完成。每個任務的費用是它的完成時刻乘以乙個費用係數\(c_i\)。
求最小的總費用。
設\(f_\)為把前i個任務分成j批的最小費用。
\(f_=min\+(s*j+sumt_i)*(sumc_i-sumc_k)\}(0\leq k
時間複雜度\(o(n^3)\)的,不能過。
考慮如何降掉一維的複雜度。發現列舉的j是為了記錄分了幾批,進而記錄累計的啟動時間,而我們可以將這個啟動時間提前累加(費用提前計算)。
具體地,將第二維去掉,\(f_i=min\\)。
即不考慮這一批任務啟動時間費用的影響,而是一起提前累加,把後面的費用(當前的也算在裡面了)都提前累加(即\(s*(sumc_n-sumc_j))\)。
時間複雜度為\(o(n^2)\),有沒有更優秀的演算法?
對於\(f_i=min\\)這個式子,我們把min去掉再化開,將只與j有關的放到一邊:
\(f_j=(sumt_i+s)*sumc_j+f_i-sumt_i*sumc_i-s*sumc_n\)
可以看出這是形如\(y=kx+b\)的東西
\((sumc_j,f_j)\)即為斜率為\(sumt_i+s\)的直線上一點。
我們發現\(f_i\)是在右邊的\(b\)中的,而其它的量都是定值,那麼我們最小化\(b\)即可最小化\(f_i\)。
那麼問題變成了從若干個決策點\((sumc_j,f_j)\)中找出使得這條直線截距最小的乙個點即為轉折點。
發現只有下凸殼的點才能作為決策點,那麼用單調佇列維護下凸殼(即斜率單調遞增)即可。
#include #include #include int n, s;
int sumt[10001], sumc[10001], f[10001], q[10001];
int main()
memset(f, 0x3f, sizeof(f));
f[0] = 0;
int l = 1, r = 1;
for (int i = 1; i <= n; i++)
printf("%d", f[n]);
}
任務安排2中,每個任務的執行時間可能為負數。
這就意味著斜率\(sumt_i+s\)並不是單調遞增的,那麼不能僅僅把隊頭作為決策點。
那麼在下凸殼上二分即可。
#include #include #include #define int long long
int n, s, l, r;
int sumt[300001], sumc[300001], f[300001], q[300001];
int find(int k)
return q[l];
}signed main()
memset(f, 0x3f, sizeof(f));
f[0] = 0;
l = 1, r = 1;
for (int i = 1; i <= n; i++)
printf("%lld", f[n]);
}
有\(m\)條貓在\(n\)座山上,山之間還有不同的距離,\(p\)個飼養員去接它們(乙個飼養員從山1走到山n)。
又知貓玩耍到\(ti\)時刻,如果飼養員在\(t\)時刻到了這座山,那麼這條貓的等待時間為\(t-t_i\)。
求所有貓最小的等待時間。
先考慮如何列出原始dp方程。
對於每只貓,設\(a_i=t_i-\sum_^ d_j\),即ai時刻出發去接貓它的等待時間為\(0\),那麼\(t\)時刻去接它,等待時間即為\(t-a_i\)。
將\(a_i\)從小到大排序,可以發現每個飼養員接的肯定是一段連續區間的貓(11112222211111,這一段代表飼養員1,2接貓的位置,可以發現前面的1歸給2接會更優)。
那麼設\(f_\)為前\(i\)個飼養員帶走前\(j\)個貓的最小等待時間。
\(f_=min\+(j-k)*t-(suma_j-suma_k)\}(0\leq k
考慮將第二維進行斜率優化。
將式子拆開,得\(f_+suma_k=a_j*k+f_-a_j*j+suma_j\)
\(a\)已經排過序了,我們可以按照「任務安排2」的操作來做這道題。
#include #include #include #define int long long
int n, m, p;
int a[100001], d[100001], s[100001], f[101][100001], q[100001], g[100001];
signed main()
std::sort(a + 1, a + m + 1);
for (int i = 1; i <= m; i++)
s[i] = s[i - 1] + a[i];
int l, r;
memset(f, 127, sizeof(f));
f[0][0] = 0;
for (int i = 1; i <= p; i++)
} printf("%lld", f[p][m]);
}
斜率優化是將dp方程化成形如\(y=kx+b\)的形式,(例任務安排2中)\(x\),\(y\)只\(j\)有關,\(k\)只與\(i\)有關,\(b\)中包含著要求的量,
那麼每個決策點\(j\)都可以表示成乙個座標系上的乙個點\((x,y)\),而每個\(i\)都有固定的\(k\)。
這一條直線通過不同的決策點會有不同的截距\(b\),這時最(大/小)化截距使得轉移進行。
斜率優化dp小結
在寫斜率優化之前,我們來回顧一下單調佇列優化的dp 1.對於如下形式的dp方程 dp i min 0 j我們直接用乙個變數維護 0,i 中dp j f j 的最小值即可 2.對於如下形式的dp方程 dp i min i m j我們可以用乙個單調佇列維護乙個 i m,j 中dp j f j 的最小值,...
斜率優化dp小結
最近刷了幾道斜率優化dp算是對斜率優化有了一定的了解了 現在來小結一下 斜率優化dp的優化能力是將n 2優化成n,n 3優化成n 2 其轉移方程一般是dp k min dp i cost i 1 k 斜率優化優化的是排除一些不可能是最優解的解,那麼什麼情況下不可能是最優解呢 下面看一道題hdu 28...
斜率優化dp小結
先推薦一篇部落格 下文有小部分修改自 有些dp方程可以轉化成dp i f i,j x i 的形式,其中f j 與i和j有關。這樣的dp方程無法直接使用單調佇列進行優化,所以考慮另外一中降低複雜度的方式 斜率優化!舉個例題 hdu 3507 設dp i 表示到i的最少花費,sum i 表示從a 1 到...