题目链接
The Last Puzzle Time Limit: 2 Seconds Memory Limit: 65536 KB Special Judge 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.
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 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.
2 4 3 0 3 2 3 3 0 3 4 5 200 1 2 0 1 2 3
1 2 Mission Impossible 1 2 4 3
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个按钮,T[ i ]表示第 i 个按钮按下后多少秒又弹起,D[ i ]表示第 i 个按钮离第1个按钮的距离,行走1的距离花1秒,按按钮不花时间,问是否存在一种按按钮的方式,让某一时刻所有按钮都被按下?如果有输出方案。
题解:这题首先要证明一个定理:要把一个区间所有的按钮按下并花费的时间最小,那么一定是从区间的端点开始按。
N<=2 显然满足。
对于N>=3的情况,假设起点为X,1<X<N。从X出发,假设对于两个端点来说先走到左端点,走到左端点后一定要走向右端端点,对于1到X这一段来说,显然,当从1走到X的时候按按钮一定比从X到1的时候按更优,所以从X到1这一段完全是浪费时间,还不如从1开始更优。假设先走到右端点同理。所以对于一个区间来说,从端点开始按一定更优。
证明了上面的定理,我们就可以用经典的区间dp的方法来做这一题。
我们用dp[ i ][ j ][0,1] 分别表示区间 [ i ,j ] 以左端点开始或者以右端点开始按,把整个区间按完要用的最短时间。
一般的转移方法就是
dp[ i ][ j ][0]=min(dp[ i +1 ] [ j ] [ 0]+cost(i,i+1), dp[ i+1 ] [ j ] [ 1 ]+cost(i,j) )
dp[ i ][ j ][1]=min(dp[ i ][ j-1 ] [0]+cost(j, i), dp[ i ] [ j-1 ] [ 1 ]+cost(j ,j-1) )
cost( i ,j )为从 i 到 j 要花的时间。
当然转移的时候我们还要限制按钮不会弹起来。
具体见代码:
//#pragma comment(linker, "/STACK:102400000,102400000") #include<stdio.h> #include<queue> #include<iostream> #include<algorithm> #include<string.h> #include<string> #include<math.h> #include<stack> #define nn 210 #define mod 1000 #define inff 0x3fffffff typedef long long LL; using namespace std; int n; int a[nn],b[nn]; int dp[nn][nn][2]; int pre[nn][nn][2]; int dfs(int l,int r,int s) { if(dp[l][r][s]!=-1) return dp[l][r][s]; int &t=dp[l][r][s]; if(l==r) return t=0; t=inff; if(s==0) { if(a[l]>dfs(l+1,r,0)+b[l+1]-b[l]) { if(dfs(l+1,r,0)+b[l+1]-b[l]<t) { t=dfs(l+1,r,0)+b[l+1]-b[l]; pre[l][r][s]=0; } } if(a[l]>dfs(l+1,r,1)+b[r]-b[l]) { if(dfs(l+1,r,1)+b[r]-b[l]<t) { t=dfs(l+1,r,1)+b[r]-b[l]; pre[l][r][s]=1; } } } else { if(a[r]>dfs(l,r-1,0)+b[r]-b[l]) { if(dfs(l,r-1,0)+b[r]-b[l]<t) { t=dfs(l,r-1,0)+b[r]-b[l]; pre[l][r][s]=0; } } if(a[r]>dfs(l,r-1,1)+b[r]-b[r-1]) { if(dfs(l,r-1,1)+b[r]-b[r-1]<t) { t=dfs(l,r-1,1)+b[r]-b[r-1]; pre[l][r][s]=1; } } } return t; } int main() { int i,j; while(scanf("%d",&n)!=EOF) { for(i=1;i<=n;i++) { scanf("%d",&a[i]); } for(i=1;i<=n;i++) { scanf("%d",&b[i]); } for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { dp[i][j][0]=dp[i][j][1]=-1; } } int ans=min(dfs(1,n,0),dfs(1,n,1)); if(ans==inff) { puts("Mission Impossible"); } else { int l=1,r=n,s; if(ans==dp[1][n][0]) s=0; else s=1; bool ok=true; while(l<=r) { if(!ok) printf(" "); else ok=false; if(s==0) { printf("%d",l); } else printf("%d",r); int tem=pre[l][r][s]; if(s==0) { l++; } else r--; s=tem; } puts(""); } } return 0; }