HDU 4362

读题很重要啊,题目读错了,害我想了一晚上。

题目大意:给你n种物品,每种物品有个坐标和价值,你得到某个物品的消耗为|x-y|+v。

而且要求你只能从第一种依次往后取,(我开始以为是随机的。。)。

所以很容易想到DP转移方程,不过需要优化下,因为dp[i][j] = min{dp[i-1][k] + |pos[i-1][k] - pos[i][k]|} + v[i][j];

主要是绝对值很碍事,所以要想办法把绝对值去掉,这里我们就可用到单调队列,一个L和R队列分别存储着从左边(从坐标来说)到这个位置的“值”,已经从右边到这个位置的“值”。

View Code
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<vector>
 6 #define MAXN 50
 7 #define MAXM 1000
 8 using namespace std;
 9 struct ball {
10     int x,val;
11 }data[MAXN][MAXM],r[MAXM],l[MAXM];
12 
13 int dp[MAXN][MAXM];
14 
15 bool cmp1(const ball &p, const ball &q)
16 {
17     return p.x < q.x || (p.x == q.x && p.val < q.val);
18 }
19 
20 bool cmp2(const ball &p, const ball &q)
21 {
22     return p.val < q.val || (p.val == q.val && p.x < q.x);
23 }
24 
25 int main()
26 {
27     int t;
28     scanf("%d",&t);
29     while (t--) {
30         int n,m,pos;
31         scanf("%d%d%d",&n,&m,&pos);
32         for (int i(0); i<n; ++i) {
33             for (int j(0); j<m; ++j) {
34                 scanf("%d",&data[i][j].x);
35             }
36         }
37         for (int i(0); i<n; ++i) {
38             for (int j(0); j<m; ++j) {
39                 scanf("%d",&data[i][j].val);    
40             }         
41         }
42         for (int i(0); i<n; ++i)sort(data[i],data[i]+m,cmp1);
43         int ans(1<<31 - 1);
44         for (int i(0); i<m; ++i)dp[0][i] = data[0][i].val + abs(data[0][i].x - pos);
45         for (int i(1); i<n; ++i) {            
46             for (int j(0); j<m; ++j) {
47                 l[j].val = dp[i-1][j] - data[i-1][j].x;
48                 r[j].val = dp[i-1][j] + data[i-1][j].x;
49                 l[j].x = r[j].x = data[i-1][j].x;                
50             }
51             sort(r,r+m,cmp2);
52             int ans1(1<<31 - 1),k2(0),k1(0),ans2(1<<31 - 1),temp1,temp2;
53             for (int j(0); j<m; ++j) {
54                 while (k1 < m && l[k1].x < data[i][j].x) {
55                     ans1 = min(ans1,l[k1].val);
56                     ++k1;
57                 }
58                 if (ans1 != (1<<31 - 1))temp1 = ans1 + data[i][j].x;
59                 else temp1 = ans1;
60                 while (k2 < m && r[k2].x < data[i][j].x) {
61                     ++k2;
62                 }
63                 if (k2 < m)ans2 = r[k2].val - data[i][j].x;
64                 else ans2 = (1<<31 - 1);
65                 dp[i][j] = min(ans2,temp1) + data[i][j].val;
66             }
67         } 
68         for (int i(0); i<m; ++i)ans = min(ans,dp[n-1][i]);
69         cout<<ans<<endl;
70     }
71     return 0;
72 }
posted on 2012-08-16 15:46  Dev-T  阅读(292)  评论(0编辑  收藏  举报