欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

POJ 1821 Fence ★(单调队列优化DP)

发布时间:2025/4/5 编程问答 44 豆豆
生活随笔 收集整理的这篇文章主要介绍了 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)的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。