HDU 4053 or ZOJ 3541 The Last Puzzle【区间dp】【经典题】
There is one last gate between the hero and the dragon. But opening the gate isn't an easy task.
There were n buttons list in a straight line in front of the gate and each with an integer on it. Like other puzzles the hero had solved before, if all buttons had been pressed down in any moment, the gate would open. So, in order to solve the puzzle, the hero must press all the button one by one.
After some trials, the hero found that those buttons he had pressed down would pop up after a while before he could press all the buttons down. He soon realized that the integer on the button is the time when the button would automatic pop up after pressing it, in units of second. And he measured the distance between every button and the first button, in units of maximum distance the hero could reach per second. Even with this information, the hero could not figure out in what order he should press the buttons. So you talent programmers, are assigned to help him solve the puzzle.
To make the puzzle easier, assuming that the hero always took integral seconds to go from one button to another button and he took no time turnning around or pressing a button down. And the hero could begin from any button.
Input
The input file would contain multiple cases. Each case contains three lines. Process to the end of file.
The first line contains a single integer n(1 ≤ n ≤200), the number of buttons.
The second line contains n integers T1, T2, ..., Tn, where Ti(1 ≤ Ti ≤ 1,000,000) is the time the ith button would automatic pop up after pressing it, in units of second.
The third line contains n integers D1, D2, ..., Dn, where Di(1 ≤ Di ≤ 1,000,000) is the time hero needed to go between the ith button and the first button, in units of second. The sequence will be in ascending order and the first element is always 0.
Output
Output a single line containing n integers which is the sequence of button to press by the hero. If there are multiply sequences, anyone will do. If there is no way for the hero to solve the puzzle, just output "Mission Impossible"(without quote) in a single line.
Sample Input
2 4 3 0 3 2 3 3 0 3 4 5 200 1 2 0 1 2 3
Sample Output
1 2 Mission Impossible 1 2 4 3
Hint
In the second sample, no matter which button the hero pressed first, the button would always pop up before he press the other button. So there is no way to make all the button pressed down.
题意:
一条直线上有n(1<=n<=200)个开关,开关i的属性d[i]表示它到最左端开关的距离,t[i]表示它被按下t[i]秒后又自动弹出。
求一个按开关的顺序,使得某时刻所有的开关都被按下。可以从任意一个开关开始,而且手移动的速度是每秒钟一个单位长度,
按开关所用的时间忽略不计。
题解:
dp[i][j][0]表示从i开始到j按完所需要的最短时间
dp[i][j][1]表示从j开始到i按完所需要的最短时间
因为dp[i][j][0]从i开始,所以上一状态为dp[i+1][j][0|1]加上i到i+1或i到j的距离,同理dp[i][j][1]为dp[i][j-1][0|1]加上j到i或j到j-1的距离。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #define INF 0x3f3f3f3f #define ms(x,y) memset(x,y,sizeof(x)) using namespace std; const double pi = acos(-1); const double eps = 1e-8; const int maxn = 210; int dp[maxn][maxn][2], n, t[maxn], d[maxn], Next[maxn][maxn][2]; int main() { while (~scanf("%d", &n)) { for (int i = 1; i <= n; i++) scanf("%d", t + i); for (int i = 1; i <= n; i++) scanf("%d", d + i); ms(dp, 0); for (int l = 2; l <= n; l++) //枚举区间长度 { for (int i = 1; i + l - 1 <= n; i++) //枚举区间左端点 { int j = i + l - 1; //区间右端点 //计算dp[i][j][0],判断左端点i到其上一步递归的距离 if (dp[i + 1][j][0] + d[i + 1] - d[i] < dp[i + 1][j][1] + d[j] - d[i]) { dp[i][j][0] = dp[i + 1][j][0] + d[i + 1] - d[i]; Next[i][j][0] = 0; } else { dp[i][j][0] = dp[i + 1][j][1] + d[j] - d[i]; Next[i][j][0] = 1; } if (dp[i][j][0] >= t[i]) //判断是否可行,当前按下i { dp[i][j][0] = INF; } //计算dp[i][j][1],判断右端点j到其上一步递归的距离 if (dp[i][j - 1][0] + d[j] - d[i] < dp[i][j - 1][1] + d[j] - d[j - 1]) { dp[i][j][1] = dp[i][j - 1][0] + d[j] - d[i]; Next[i][j][1] = 0; } else { dp[i][j][1] = dp[i][j - 1][1] + d[j] - d[j - 1]; Next[i][j][1] = 1; } if (dp[i][j][1] >= t[j]) //判断是否可行,当前按下j { dp[i][j][1] = INF; } } } int l, r, m; if (dp[1][n][0] < INF) { l = 2; r = n; m = Next[1][n][0]; printf("1"); } else if (dp[1][n][1] < INF) { l = 1; r = n - 1; m = Next[1][n][1]; printf("%d", n); } else { printf("Mission Impossible\n"); continue; } while (l <= r) { if (m == 0) //下一步从左走 { printf(" %d", l); m = Next[l][r][0]; l++; } else { printf(" %d", r); m = Next[l][r][1]; r--; } } printf("\n"); } }