hdu 4362
地址:http://acm.hdu.edu.cn/showproblem.php?pid=4362
题意:挖宝石,宝石都出现在一条直线上,每次出现n个宝石,只能挖其中一个,剩下消失。总共有m次机会。精力消耗有路程的消耗和挖宝石的时候消耗,求最小消耗。
mark:dp。维护两个最值,把问题分成从位置大于和小于目前位置两种情况讨论。dp[i][j]代表第i段时间挖第j个石头消耗最小。
首先只考虑位置比目前小的情况,dp[i][j] = min{dp[i-1][k]+p[i][j]-p[i-1][k]+e[i][j]} = min{dp[i-1][k]-p[i-1][k]}+p[i][j]+e[i][j];用一点单调队列的思想。
代码:
#include <stdio.h> #include <string.h> #include <stdlib.h> typedef struct { int p,e; }ball; const int M = 55; const int N = 1010; ball b[M][N]; int m,n,x; int dp[M][N]; int cmp(const void *a, const void *b) { return (*(ball *)a).p - (*(ball *)b).p; } int fab(int a) {return a < 0 ? -a : a;} int min(int a, int b) {return a < b ? a : b;} void solve() { int i,j,k; int mm; for(i = 1; i < m; i++) { k = 0; mm = 10000000; for(j = 0; j < n; j++) { while(k < n && b[i][j].p >= b[i-1][k].p) { mm = min(dp[i-1][k]-b[i-1][k].p, mm); k++; } dp[i][j] = mm+b[i][j].p+b[i][j].e; } k = n-1; mm = 10000000; for(j = n-1; j >= 0; j--) { while(k >= 0 && b[i][j].p <= b[i-1][k].p) { mm = min(dp[i-1][k]+b[i-1][k].p, mm); k--; } dp[i][j] = min(dp[i][j], mm-b[i][j].p+b[i][j].e); } } } int main() { int t; int i,j; scanf("%d", &t); while(t-- && scanf("%d%d%d", &m, &n, &x)) { for(i = 0; i < m; i++) for(j = 0; j < n; j++) scanf("%d", &b[i][j].p); for(i = 0; i < m; i++) { for(j = 0; j < n; j++) scanf("%d", &b[i][j].e); qsort(b[i], n, sizeof(b[1][1]), cmp); } for(i = 0; i < n; i++) dp[0][i] = fab(x-b[0][i].p)+b[0][i].e; solve(); int min1 = dp[m-1][0]; for(i = 1; i < n; i++) min1 = min(min1, dp[m-1][i]); printf("%d\n", min1); } return 0; }