HDU4362Dragon Ball【dp优化】



【比赛提醒】BestCoder 你报名了吗?(点击报名) 
【科普】什么是BestCoder?如何参加?

Dragon Ball

Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 2196    Accepted Submission(s): 767

Problem Description

Sean has got a Treasure map which shows when and where the dragon balls will appear. some dragon balls will appear in a line at the same time for each period.Since the time you got one of them,the other dragon ball will disappear so he can only and must get one Dragon ball in each period.Digging out one ball he will lose some energy.Sean will lose |x-y| energy when he move from x to y.Suppose Sean has enough time to get any drogan ball he want in each period.We want to know the minimum energy sean will lose to get all period’s dragon ball.

Input

In the first line a number T indicate the number of test cases.Then for each case the first line contain 3 numbers m,n,x(1<=m<=50,1<=n<=1000),indicate m period Dragon ball will appear,n dragon balls for every period, x is the initial location of sean.Then two m*n matrix. For the first matrix,the number in I row and J column indicate the location of J-th Dragon ball in I th period.For the second matrix the number in I row and J column indicate the energy sean will lose for J-th Dragon ball in I-th period.

Output

For each case print a number means the minimum energy sean will lose.

Sample Input

1
3 2 5
2 3
4 1
1 3
1 1
1 3
4 2

Sample Output

8

Author

FZU

Source

2012 Multi-University Training Contest 7

这个题卡死我了啊啊啊啊啊啊啊啊啊

终于找到错了啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊

啊啊啊啊啊啊啊啊

大意:有n个periodm个龙珠

每个period会出现一些龙珠

但是你每个period只能收集一个龙珠

告诉你每个龙珠在每个时期出现的位置和digging的cost

问最少花费多少cost

分析:

刚开始读错题意了  题目描述?额出问题了?我以为每个水晶球去过之后就不能去了呢

又是1000状态压缩都没法压

之后看到正确题意之后第一反应出来一个10^7的算法

交了一次TLE

之后我就想怎么优化

看别人题意的时候看到他说用单调队列优化

我想了大概十分钟才终于想通了

对于一个位置pos

dp[i][j] = min(dp[i - 1][k] + abs(pos - k) + cost[i][j])

将其展开

对于pos之前的额k

dp[i][j] = min(dp[i - 1][k] + pos - k + cost[i][j])

对于之后的k

dp[i][j] = min(dp[i - 1][k] + k - pos+ cost[i][j])

我的思路是把每个period的位置都排一次序

对于dp[i][j]只要正着扫一遍k用一个单调队列

然后在倒着扫一遍

然后就wa啊

后来才找到wa点

我们每次往单调队列里push的不能跟当前状态有任何关系==

以为他会影响到后续状态==

只要把dp方程改一下

pos之前的k dp[i][j] = min(dp[i - 1][k] - pos[i - 1][k]) + pos[i][j] + cost[i][j]

pos之后的k dp[i][j] = min(dp[i - 1][j] + pos[i - 1][k]) + cost[i][j] - pos[i][j]

代码:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <queue>
 5 #include <algorithm>
 6 using namespace std;
 7
 8 const int maxn = 55;
 9 const int maxm = 1005;
10 const int INF = 1000000000;
11
12 struct Node {
13     int x, y, pos;
14 }node[maxn][maxm];
15 bool cmp(Node n1, Node n2) {
16     return n1.pos < n2.pos;
17 }
18 int cost[maxn][maxm];
19 int dp[maxn][maxm];
20 priority_queue<int, vector<int>, greater<int> > q1, q2;
21
22 int main() {
23     int t, n, m, x;
24     scanf("%d",&t);
25     while(t--) {
26         scanf("%d %d %d",&n, &m, &x);
27         for(int i = 1; i <= n; i++) {
28             for(int j = 1; j <= m; j++) {
29                 scanf("%d",&node[i][j].pos);
30                 node[i][j].x = i; node[i][j].y = j;
31             }
32         }
33         for(int i = 1; i <= n; i++) {
34             for(int j = 1; j <= m; j++) {
35                 scanf("%d",&cost[i][j]);
36             }
37         }
38         for(int i = 1; i <= n; i++) {
39             sort(node[i] + 1, node[i] + 1 + m, cmp);
40         }
41         memset(dp, 0x3f, sizeof(dp));
42         for(int j = 1; j <= m; j++) {
43             dp[1][j] = abs(x - node[1][j].pos) + cost[node[1][j].x][node[1][j].y];
44         }
45         for(int i = 2; i <= n; i++) {
46             int k = 1;
47             while(!q1.empty()) q1.pop();
48             while(!q2.empty()) q2.pop();
49             for(int j = 1; j <= m; j++) {
50                 for(k; k <= m; k++) {
51                     if(node[i - 1][k].pos > node[i][j].pos) {
52                         break;
53                     }
54                     q1.push(dp[i - 1][k] - node[i - 1][k].pos);
55                 }
56                 if(!q1.empty()) {
57                     dp[i][j] = min(dp[i][j], q1.top() + node[i][j].pos + cost[node[i][j].x][node[i][j].y]);
58                 }
59             }
60             k = m;
61             for(int j = m; j >= 1; j--) {
62                 for(k; k >= 1; k--) {
63                     if(node[i - 1][k].pos < node[i][j].pos) break;
64                     q2.push(dp[i - 1][k] + node[i - 1][k].pos);
65                 }
66                 if(!q2.empty()) {
67                     dp[i][j] = min(dp[i][j], q2.top() + (- node[i][j].pos + cost[node[i][j].x][node[i][j].y]));
68                 }
69             }
70         }
71         int ans = INF;
72
73         for(int j = 1; j <= m; j++) {
74             ans = min(ans, dp[n][j]);
75         }
76         printf("%d\n", ans);
77     }
78     return 0;
79 }

时间: 2024-10-07 16:25:19

HDU4362Dragon Ball【dp优化】的相关文章

常见的DP优化类型

常见的DP优化类型 1单调队列直接优化 如果a[i]单调增的话,显然可以用减单调队列直接存f[j]进行优化. 2斜率不等式 即实现转移方程中的i,j分离.b单调减,a单调增(可选). 令: 在队首,如果g[j,k]>=-a[i],那么j优于k,而且以后j也优于k,因此k可以重队列中直接删去.在队尾,如果x<y<z,且g[x,y]<=g[y,z],也就是说只要y优于x一定可以得出z优于y的,我们就删去y. 经过队尾的筛选,我们在队列中得到的是一个斜率递减的下凸包,每次寻找从上往下被-

hdu5009 离散化+dp+优化

西安网络赛C题.先对大数据离散化,dp优化 #include<iostream> //G++ #include<vector> #include<cstdio> #include<algorithm> #include<cstring> #include<string> #include<queue> #include<cmath> using namespace std; const int maxn=512

LCIS tyvj1071 DP优化

思路: f[i][j]表示n1串第i个与n2串第j个且以j结尾的LCIS长度. 很好想的一个DP. 然后难点是优化.这道题也算是用到了DP优化的一个经典类型吧. 可以这样说,这类DP优化的起因是发现重复计算了很多状态,比如本题k的那层循环. 然后就可以用maxl标记搞一下,将O(n^3)变成O(n^2). #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> usi

loj6171/bzoj4899 记忆的轮廊(期望dp+优化)

题目: https://loj.ac/problem/6171 分析: 设dp[i][j]表示从第i个点出发(正确节点),还可以有j个存档点(在i点使用一个存档机会),走到终点n的期望步数 那么 a[i][k]表示i点为存档点,从i点走到k点(正确节点)的期望步数(中间没有其它存档点) 那么a[i][j]可以递推预处理出 其中g[v]表示从一个错误节点v开始走,期望走g[v]步会读档 解方程可以解出 s[j-1]就是点j-1出去的所有错误儿子的g[v]之和 那么接下来只要知道如何求g[v]就行了

poj1088 滑雪(dfs、dp优化)

#include <iostream> #include <map> #include <string> #include <cstdio> #include <sstream> #include <cstring> #include <vector> #include <cmath> #define N 110 int a,b,step=0; int anw=0; int moun[N][N]; int dp

dp优化1——sgq(单调队列)

该文是对dp的提高(并非是dp入门,dp入门者请先参考其他文章) 有时候dp的复杂度也有点大...会被卡. 这几次blog大多数会讲dp优化. 回归noip2017PJT4.(题目可以自己去百度).就是个很好的案例.那题是个二分套dp如果dp不优化复杂度O(n^2logn)还能拿60分(CCF太仁慈了,如果是我直接给10分). 正解加上个单调队列(其实是sliding window)O(nlogn) 我们发现,此类dp是这样的 状态i是由[l,r]转移过来的.且i在向右移动的过程中,[l,r]一

7.14 单调栈 单调队列 +dp优化

单调栈和单调队列的定义具体看ppt了 模板: 单调队列 head =1; tail = 0; rep( i ,1 ,n ){ while( head <= tail && a[i] < dq[tail].first)tail--; while( head <= tail && dq[head].second < i-k+1) head++; dq[ ++tail ]={a[i] ,i}; 例题:https://vjudge.net/contest/3

dp优化总结

dp优化总结 一.滚动数组 典型的空间优化. 这应该是最最普通的一个优化了吧.. 对于某些状态转移第i个只需要用到第i-1个状态时,就可以用滚动数组,把第一维用0/1表示. 拓展1: 当一个状态转移要用到前m个转移时,我们依然可以滚起来,把第一维按模m的值滚起来. 拓展2: 若每一个决策可以选任意次(在一定限度下),那么我们可以借鉴完全背包的思路,把决策一个一个累计起来,起到优化时间的作用.(例题:NOIP2013 飞扬的小鸟) 二.数据结构优化 1.单调队列 如果一个转移方程模型大致如下: \

HDU 4362 Dragon Ball(维护最小值DP优化)

 题意: 在连续的 n 秒中,每秒会出现 m 个龙珠,出现之后会立即消失,知道了第一秒所在的位置,每从一个位置移动到另一个位置的时候,消耗的价值为 abs(i-j), 知道了次出现的龙珠的价值,问 n 秒之后得到的最大价值是多少. 思路:这道题朴素的做法时间复杂度为O(n*n*m)勉强可以水过去,正解应该是用单调队列的思路维护最小值优化. 由状态转移方程dp[i][j] = min{ dp[i-1][k] + abs(pos[i-1][k]-pos[i][j]) } + cost[i][j]