题意:有m个阶段,每个阶段都有n个龙珠,当在某一阶段选择一个龙珠,该阶段其他龙珠都会消失。给出两个m*n的矩阵,第一个矩阵表示消灭第i个阶段第j个龙珠的位置,第二个矩阵表示取第i个阶段第j个龙珠消耗的能量,同时当第x个位置到第个位置需要消耗 | y - x|的能量。问最后每个阶段取走一个龙珠最小的能量消耗。


解题思路:dp[i][j]表示第i个阶段选择第j个龙珠的最小耗能。

转移方程:dp[i][j] = min{dp[i-1][k] + abs(loc[i][j] - loc[i-1][k]) + cost[i][j]},这里需要枚举的是i,j,k所以时间复杂度O(M*N*N),这题数据好像卡得不是很紧,所以运气好点是可以AC的。不过不是正解。

这里可以利用单调队列。因为dp[i][j]=min{dp[i-1][k] - loc[i-1][k] + loc[i][j] + cost[i][j]}  (loc[i][j] > loc[i-1][k]),所以可以只需要维护dp[i-1][k] - loc[i-1][k]即可。由于有绝对值,所以我这里用了两个单调队列,一个维护dp[i-1][k] - loc[i-1][k],另一个维护dp[i-1][k] + loc[i-1][k],但不知道什么原因WA了。。。

先放在这里,等以后有思路了再改吧。。也希望路过我博客的哪位大神指点指点。



#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;const int maxn = 1005;
const int inf = 0x3f3f3f3f;
struct Node
{int pos,cost;
}mat[55][maxn];
int n,m,x;
int dp[55][maxn],q1[maxn],q2[maxn],h1,h2,t1,t2;bool cmp(Node a,Node b)
{return a.pos < b.pos;
}int main()
{int t;scanf("%d",&t);while(t--){scanf("%d%d%d",&m,&n,&x);memset(dp,inf,sizeof(dp));for(int i = 1; i <= m; i++)for(int j = 1; j <= n; j++)scanf("%d",&mat[i][j].pos);for(int i = 1; i <= m; i++){for(int j = 1; j <= n; j++)scanf("%d",&mat[i][j].cost);sort(mat[i]+1,mat[i]+1+n,cmp);<span style="white-space:pre">    </span>//排序为了保证进入队列时,位置是递增的}for(int i = 1; i <= n; i++)dp[1][i] = abs(x - mat[1][i].pos) + mat[1][i].cost;for(int i = 2; i <= m; i++){h1 = h2 = t1 = t2 = 0;for(int j = 1; j <= n; j++) //将dp[i-1]层的最优状态放入单调队列{while(h1 < t1 && dp[i-1][j] - mat[i-1][j].pos <= dp[i-1][q1[t1-1]] - mat[i-1][q1[t1-1]].pos) t1--;q1[t1++] = j;while(h2 < t2 && dp[i-1][j] + mat[i-1][j].pos <= dp[i-1][q2[t2-1]] + mat[i-1][q2[t2-1]].pos) t2--;q2[t2++] = j;}for(int j = 1; j <= n; j++){while(h1 < t1 && mat[i][j].pos < mat[i-1][q1[h1]].pos) h1++;dp[i][j] = dp[i-1][q1[h1]] + mat[i][j].pos + mat[i][j].cost;while(h2 < t2 && mat[i][j].pos >= mat[i-1][q2[h2]].pos) h2++;dp[i][j] = min(dp[i][j],dp[i-1][q2[h2]] - mat[i][j].pos + mat[i][j].cost);}}int ans = inf;for(int i = 1; i <= n; i++)ans = min(ans,dp[m][i]);printf("%d\n",ans);}return 0;
}

PS: 仔细想了想,确实自己的单调队列有问题,因为我是先把所有的dp[i-1]层的送入队列,就会出现问题,在我后面的循环枚举dp[i]层的时候一些有效位置可能不在队列里。所以参考了别人的代码,还是要先枚举dp[i][j]中的j,保证我先选择第j个位置,由于已经是有序的了,所以就直接找不大于mat[i][j].pos位置的最小值即可,同理,由于有绝对值,所以还要反着循环一次。

详细的过程看代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;const int maxn = 1005;
const int inf = 0x3f3f3f3f;
struct Node
{int pos,cost;
}mat[55][maxn];
int n,m,x;
int dp[55][maxn],q1[maxn],q2[maxn],h1,h2,t1,t2;bool cmp(Node a,Node b)
{return a.pos < b.pos;
}int main()
{int t;scanf("%d",&t);while(t--){scanf("%d%d%d",&m,&n,&x);memset(dp,inf,sizeof(dp));for(int i = 1; i <= m; i++)for(int j = 1; j <= n; j++)scanf("%d",&mat[i][j].pos);for(int i = 1; i <= m; i++){for(int j = 1; j <= n; j++)scanf("%d",&mat[i][j].cost);sort(mat[i]+1,mat[i]+1+n,cmp);}for(int i = 1; i <= n; i++)dp[1][i] = abs(x - mat[1][i].pos) + mat[1][i].cost;for(int i = 2; i <= m; i++){int k = 1, Min = inf;for(int j = 1; j <= n; j++){while(k <= n && mat[i][j].pos >= mat[i-1][k].pos){Min = min(Min,dp[i-1][k] - mat[i-1][k].pos);k++;}dp[i][j] = Min + mat[i][j].pos + mat[i][j].cost;}k = n, Min = inf;for(int j = n; j >= 1; j--){while(k >= 1 && mat[i][j].pos <= mat[i-1][k].pos){Min = min(Min,dp[i-1][k] + mat[i-1][k].pos);k--;}dp[i][j] = min(dp[i][j],Min - mat[i][j].pos + mat[i][j].cost);}}int ans = inf;for(int i = 1; i <= n; i++)ans = min(ans,dp[m][i]);printf("%d\n",ans);}return 0;
}

hdu 4362(单调队列优化dp)相关推荐

  1. hdu 3401(单调队列优化dp)

    注意:这题题意是有操作的天数相隔要大于w 然后列出状态转移方程就可以发现,可以用优点队列优化啦. 构造状态dp[i][j]表示第i 天拥有 j只股票的时候,赚了多少钱 状态转移有: 1.从前一天不买不 ...

  2. hdu 3401 Trade(单调队列优化dp)

    hdu 3401 Trade(单调队列优化dp) 题意:lxhgww喜欢炒股票,他可以在第i天买入或者卖出若干张股票(一天只能买或者卖),两个交易日之间至少相隔w天,问他t天后最多能赚多少. 解题思路 ...

  3. 算法笔记--单调队列优化dp

    单调队列:队列中元素单调递增或递减,可以用双端队列实现(deque),队列的前面和后面都可以入队出队. 单调队列优化dp: 问题引入: dp[i] = min( a[j] ) ,i-m < j ...

  4. poj 2373(单调队列优化dp)

    在长为L(<=1000000)的草地(可看成线段)上装喷水头,喷射是以这个喷水头为中心,喷水头的喷洒半径是可调节的调节范围为[a,b].要求草地的每个点被且只被一个喷水头覆盖,并且有些连续区间必 ...

  5. poj 1821(单调队列优化dp)

    题意:有一道线性篱笆由N个连续的木板组成.有K个工人,你要叫他们给木板涂色.每个工人有3个参数:L 表示 这个工人可以涂的最大木板数目,S表示这个工人站在哪一块木板,P表示这个工人每涂一个木板可以得到 ...

  6. 洛谷P3195 [HNOI2008]玩具装箱TOY(单调队列优化DP)

    题目描述 P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中.P教授有编号为1...N的N件玩具, ...

  7. 【计蒜客 - 蓝桥训练】蒜厂年会(单调队列优化dp,循环数列的最大子段和)

    题干: 在蒜厂年会上有一个抽奖,在一个环形的桌子上,有 nn 个纸团,每个纸团上写一个数字,表示你可以获得多少蒜币.但是这个游戏比较坑,里面竟然有负数,表示你要支付多少蒜币.因为这些数字都是可见的,所 ...

  8. 单调队列以及单调队列优化DP

    单调队列定义: 其实单调队列就是一种队列内的元素有单调性的队列,因为其单调性所以经常会被用来维护区间最值或者降低DP的维数已达到降维来减少空间及时间的目的. 单调队列的一般应用: 1.维护区间最值 2 ...

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

    题解 以前做过很多单调队列优化DP的题. 这个题有一点不同是对于有的状态可以转移,有的状态不能转移. 然后一堆边界和注意点.导致写起来就很难受. 然后状态也比较难定义. dp[i][j]代表前i个人涂 ...

最新文章

  1. mysql 4字节utf8_MySQL 4字节utf8字符更新失败一例
  2. 程序员熬夜写代码,用C/C++打造一个安全的即时聊天系统
  3. 导出oracle数据c#代码,C# 程序导入导出oracle数据库
  4. java 批量替换字符串_# Java 一步一步实现高逼格的字符串替换工具(二)
  5. 漫画算法python版下载_用 Python 下载漫画
  6. Nhibernate工具Profiler配置
  7. 推荐系统的主要算法(1)
  8. 遗传算法求解多元函数极值点-C++实现
  9. [Accessibility] ****************** Loading GAX Client Bundle ****************
  10. MLX90614 非接触式红外测温
  11. 网络故障排除的5款软件, 快速解决网络故障问题
  12. ocpc php,oCPC匹配词很乱怎么办?| SEM问答
  13. 国内部分视频剪辑软件使用总结
  14. Swing关于JButton去除点击后的内边框的问题纪要!
  15. 机器学习学习笔记-多项式中的过拟合,泛化能力等
  16. Informatica任务卡在timeout based commit point
  17. 导出iPhone应用crash日志步骤说明
  18. 操作系统作业 -期末考试选择题
  19. 基于SSM开发校园外卖零食购物商城系统
  20. 自动注册activex控件

热门文章

  1. excel 中的文本是ansi还是unicode_详细讲解Excel中常用的文本函数
  2. 直播预告丨行业大咖带你找到游戏企业经营新升级的正确打开方式
  3. 神策数据颜含:流量见顶与监管趋严的双重压力下,大文娱产品如何突围?
  4. [BZOJ] 3191 [JLOI2013]卡牌游戏
  5. react antd 动态表单
  6. IE浏览器打不开解决的方法
  7. centos7修改密码
  8. Exchange 2010通过NAT方式发布到公网
  9. Windows下完成端口移植Linux下的epoll
  10. boolean searching, it is so important for searching your papers