UVa 10201 Adventures in Moving(简单DP)
题意:
有一辆车,原始装有100L汽油,到达距离为d的目的地,中间有x个加油站,每升油的价格为p。
汽车每跑一公里耗油1L,求到达目的地油箱仍然有100L的最小花费。
思路:
动归方程算是简单的,主要是要思考清楚,在第i个加油站加不加油,如果加油加k升的最小花费。
dp[i, j]表示在第i个加油站油箱有j升油的最小花费:
1. 在i站不加油 dp[i, j] = dp[i-1, j+di]; di为i-1到i的距离
2. 在i站加k升油 dp[i][j] = min(dp[i][j], dp[i-1][j-k+di] + k * p[i]);
初始状态为:dp[0, 100] = 0 其它的都是不可到达状态,赋值int_max
#include <cstdio> #include <cstdlib> #include <cstring> #include <climits> #include <algorithm> using namespace std; int dp[110][210]; int d[110], p[110]; char str[100]; int dis, n; void init_input() { gets(str); sscanf(str, "%d", &dis); n = 0; d[0] = 0; while (gets(str) != NULL) { if (str[0] == '\0') break; ++n; sscanf(str, "%d %d", &d[n], &p[n]); if (d[n] > dis) --n; } } void solve_dp() { for (int i = 0; i <= n; ++i) for (int j = 0; j <= 200; ++j) dp[i][j] = INT_MAX; dp[0][100] = 0; for (int i = 1; i <= n; ++i) { int w = d[i] - d[i-1]; for (int j = 0; j + w <= 200; ++j) if (dp[i-1][j+w] != INT_MAX) dp[i][j] = dp[i-1][j+w]; for (int j = 0; j <= 200; ++j) for (int k = 0; k <= j; ++k) if (j-k+w <= 200 && dp[i-1][j-k+w] != INT_MAX) dp[i][j] = min(dp[i][j], dp[i-1][j-k+w] + k * p[i]); } if (100 < dis - d[n] || dp[n][100+dis-d[n]] == INT_MAX) printf("Impossible\n"); else printf("%d\n", dp[n][100+dis-d[n]]); } int main() { int cases; gets(str); sscanf(str, "%d", &cases); gets(str); while (cases--) { init_input(); solve_dp(); if (cases) printf("\n"); } return 0; }
-------------------------------------------------------
kedebug
Department of Computer Science and Engineering,
Shanghai Jiao Tong University
E-mail: kedebug0@gmail.com
GitHub: http://github.com/kedebug
-------------------------------------------------------