题目大意:跑跑卡丁车是时下一款流行的网络休闲游戏,你可以在这虚拟的世界里体验驾驶的乐趣。这款游戏的特别之处是你可以通过漂移来获得一种
加速卡,用这种加速卡可以在有限的时间里提高你的速度。为了使问题简单化,我们假设一个赛道分为L段,并且给你通过每段赛道的普通耗时Ai和用加速卡的耗时Bi。加速卡的获得机制是:普通行驶的情况下,每通过1段赛道,可以获得20%的能量(N2O).能量集满后获得一个加速卡(同时能量清0).加速卡最多可以储存2个,也就是说当你有2个加速卡而能量再次集满,那么能量清零但得不到加速卡。一个加速卡只能维持一段赛道,游戏开始时没有加速卡。 问题是,跑完n圈最少用时为多少?
解题思路:将每一圈的赛段连接起来
用dp[i][j][k]表示跑完第i个赛段,有j瓶气,能量为k的花费的最小时间
(k的0,1,2,3,4分别代表20%,40%。。。)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 10010;
const int INF = 0x3f3f3f3f;
int A[N], B[N];
int dp[N][3][6];
int n, m;
void init() {
for (int i = 0; i < n; i++) {
scanf("%d" , &A[i]);
for (int j = 1; j < m; j++)
A[j * n + i] = A[i];
}
for (int i = 0; i < n; i++) {
scanf("%d", &B[i]);
for (int j = 1; j < m; j++)
B[j * n + i] = B[i];
}
}
void solve() {
memset(dp, 0x3f, sizeof(dp));
dp[0][0][1] = A[0];
for (int i = 1; i < 4; i++)
dp[i][0][i + 1] = dp[i - 1][0][i] + A[i];
dp[4][1][0] = dp[3][0][4] + A[4];
for (int i = 5; i < n * m; i++)
for (int j = 0; j < 3; j++)
for (int k = 0; k < 5; k++) {
if (dp[i - 1][j][k] != INF) {
if (j >= 1) dp[i][j - 1][k] = min( dp[i][j-1][k], dp[i - 1][j][k] + B[i]); //用气
//普通模式,跑完后刚好蓄满一瓶气
if (k == 4) {
if (j != 2) dp[i][j + 1][0] = min(dp[i][j + 1][0], dp[i - 1][j][k] + A[i]);
else dp[i][j][0] = min( dp[i][j][0], dp[i - 1][j][k] + A[i]);
}
else {
//普通模式的普通情况,跑完后无法蓄满气
dp[i][j][k + 1] = min( dp[i][j][k + 1], dp[i-1][j][k] + A[i]);
}
}
}
int ans = INF;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 5; j++)
ans = min(dp[n * m - 1][i][j], ans);
printf("%d\n", ans);
}
int main() {
while (scanf("%d%d", &n, &m) != EOF) {
init();
solve();
}
return 0;
}