[区间DP]ZOJ3541 The Last Puzzle
[区间DP]ZOJ3541 The Last Puzzle
题面
给你N个按钮,每个按钮有个位置和复原的时间,每秒可以移动单位距离,给出一种方案使得所有按钮在一个时刻全被按下
题解
先考虑可行性
容易发现对于区间[L,R]最开始按的不是L就是R
另dp[i][j][0]表示[i,j]从左边开始按
dp[i][j][1]表示从右边按
显然[i,j]可以从[i+1,j]和[i,j-1]转移而来
转移时记录选的左边还是右边即可解决输出方案
#include<bits/stdc++.h> using namespace std; const int MAXN = 200 + 10; inline int read() { int f=1,x=0; char ch; do { ch=getchar(); if(ch=='-') f=-1; }while(ch<'0'||ch>'9'); do { x=(x<<3)+(x<<1)+ch-'0'; ch=getchar(); }while(ch>='0'&&ch<='9'); return f*x; } int n; int dp[MAXN][MAXN][2]; int d[MAXN]; int t[MAXN]; int next[MAXN][MAXN][2]; int main() { while(~scanf("%d",&n)) { for(register int i=1;i<=n;i++) t[i]=read(); for(register int i=1;i<=n;i++) d[i]=read(); memset(dp,0,sizeof(dp)); for(register int len=2;len<=n;len++) { for(register int i=1;i+len-1<=n;i++) { int j=i+len-1; dp[i][j][0]=min(dp[i+1][j][0]+d[i+1]-d[i],dp[i+1][j][1]+d[j]-d[i]); next[i][j][0]=(dp[i+1][j][0]+d[i+1]-d[i]>dp[i+1][j][1]+d[j]-d[i]); if(dp[i][j][0]>=t[i]||dp[i][j][0]>=(1<<30)) dp[i][j][0]=1<<30; dp[i][j][1]=min(dp[i][j-1][0]+d[j]-d[i],dp[i][j-1][1]+d[j]-d[j-1]); next[i][j][1]=(dp[i][j-1][0]+d[j]-d[i]>dp[i][j-1][1]+d[j]-d[j-1]); if(dp[i][j][1]>=t[j]||dp[i][j][1]>=(1<<30)) dp[i][j][1]=1<<30; } } if(dp[1][n][0]<(1<<30)) { printf("1"); int l=2,r=n; int flag=next[1][n][0]; while(l<=r) { if(!flag) { printf(" %d",l); flag=next[l][r][0]; l++; } else { printf(" %d",r); flag=next[l][r][1]; r--; } } cout<<endl; } else if(dp[1][n][1]<(1<<30)) { printf("%d" ,n); int l=1,r=n-1; int flag=next[1][n][1]; while(l<=r) { if(!flag) { printf(" %d",l); flag=next[l][r][0]; l++; } else { printf(" %d",r); flag=next[l][r][1]; r--; } } cout<<endl; } else cout<<"Mission Impossible"<<endl; } }