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 }