POJ 1821 Fence ★(单调队列优化DP)
生活随笔
收集整理的這篇文章主要介紹了
POJ 1821 Fence ★(单调队列优化DP)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目大意:有一道線性籬笆由N個連續的木板組成。有K個工人,你要叫他們給木板涂色。每個工人有3個參數:L 表示 這個工人可以涂的最大木板數目,S表示這個工人站在哪一塊木板,P表示這個工人每涂一個木板可以得到的錢。要注意的是,工人i可以選擇不涂任何木板,否則,他的涂色區域必須是連續的一段,并且S[i]必須包含在內。 最后還有,每塊木板只能被涂一次。 ? 狀態方程比較容易想:dp[i][j]表示第i個人刷的最后一面墻是j時的最大獲利,則 dp[i][j]=max(dp[i-1][k]+(j-k)*p[i]) j-l[i]+1<=k+1<=s[i] ? ? ? ? (*) dp[i][j]=max(dp[i-1][j],dp[i][j-1],dp[i][j])//第i個人不刷,第j面墻不刷 ? 但是O(k*n^2)的復雜度顯然不能接受。而針對(*)這種“特殊”的轉移方程,我們可以用單調隊列把它優化到O(1): dp[i][j]=max(dp[i-1][k]-k*p[i])+j*p[i] 其中j*p[i]在i,j兩重循環中相當于常數,所以,對于狀態dp[i][j]只要單調隊列維護dp[i-1][k]-k*p[i]的最大值即可 ? 單調隊列維護過程(可以回過頭看看POJ 2823---單調隊列的模型): 單調隊列具體的做法是:最外層循環為i,首先把j=1~s[i]-1轉移完(因為它不涉及第三個轉移),然后把(j-l[i]<=k<=s[i]-1)的決策點的F[i-1,k]-p[i]*k依次入隊建立“入隊早晚時間遞增,F[i-1,k]-p[i]*k的值遞減”的單調隊列,接下來循環j=s[i]~s[i]+l[i]-1,進行這三個轉移(第三個轉移只需要用隊首元素),其中每次需要把隊首超出長度限制的決策點出隊;最后把剩下的到n循環完,只需要前兩個轉移。 ?
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MID(x,y) ((x+y)>>1)
using namespace std;
typedef long long LL;
struct worker{int l, p, s;
}w[105];
bool cmp(worker a, worker b){return a.s < b.s;
}
int f[105][16005];
int n,k;
void debug(){for (int i = 0; i <= k; i ++){for (int j = 0; j <= n; j ++)printf("%d %d %d\n", i, j, f[i][j]);}
}
deque Q;
void initQ(){while(!Q.empty())Q.pop_back();
}
int main(){scanf("%d %d", &n, &k);for (int i = 1; i <= k; i ++)scanf("%d %d %d", &w[i].l, &w[i].p, &w[i].s);sort(w+1, w+k+1, cmp); //別忘了先按S排序!for (int i = 1; i <= k; i ++){for (int j = 0; j < w[i].s; j ++)f[i][j] = max(f[i-1][j], f[i][j-1]);//單調隊列initQ();for (int j = max(0, w[i].s - w[i].l); j < w[i].s; j ++){while(!Q.empty() && f[i-1][Q.back()] - Q.back()*w[i].p <= f[i-1][j] - j*w[i].p)Q.pop_back();Q.push_back(j);}for (int j = w[i].s; j < min(w[i].s + w[i].l, n+1); j ++){while (!Q.empty() && Q.front() < j - w[i].l)Q.pop_front();f[i][j] = max(f[i-1][j], f[i][j-1]);f[i][j] = max(f[i][j], f[i-1][Q.front()] - Q.front()*w[i].p + j * w[i].p);
// 樸素DP:
// for (int p = max(0, j - w[i].l); p <= j; p ++)
// f[i][j] = max(f[i][j], f[i-1][p] + (j - p)*w[i].p);}for (int j = w[i].s + w[i].l; j <=n; j ++)f[i][j] = max(f[i-1][j], f[i][j-1]);}debug();int res = 0;for (int j = 1; j <= n; j ++)res = max(res, f[k][j]);printf("%d\n", res);return 0;
}
?
轉載于:https://www.cnblogs.com/AbandonZHANG/archive/2013/02/21/4114223.html
總結
以上是生活随笔為你收集整理的POJ 1821 Fence ★(单调队列优化DP)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎么在电脑设wifi密码忘记了怎么办 电
- 下一篇: 电脑历史怎么删除不了 电脑历史无法清除的