ZOJ3541与时间相关的区间dp+记录路径

来源:互联网 发布:淘宝京东商城 编辑:程序博客网 时间:2024/05/24 04:30

与时间相关的区间dp+记录路径

题意:

一个英雄深陷龙穴,现在有一个门,不过想把门打开需要把门上的按钮全部在同一时间都是按下状态,按钮排成一排:每一个按钮都有两个属性:

  1. 按下的状态能维持ai 个单位时间
  2. 按钮之间有距离,具体就是离第一个按钮的距离

问:英雄是否能使得全部 的按钮在同一时间都保持被按下的状态?如果可以请输出按按钮的顺序,如果不能输出一个字符串。

思路:

先普及一个知识:一个区间如果想遍历完,并且是时间最短,自然就是只能从两端开始,这样会把时间最短。

对于本题来说:遍历所有按钮的时间越短就会使得被按下按钮维持的时间更充裕

所以:对于一排按钮有两种可能

  1. 从左到右按下
  2. 从右到左按下

定义:

dp[i][j][0]
表示从第i到第j的所有按钮被按下的最短时间,第三维0表示第i到第j是从做到右

dp[i][j][1]
表示从第i到第j的所有按钮被按下的最短时间,第三维1表示第i到第j是从右到左。

那么只需要遍历区间就行了,对于每一次判断从右还是从左只需单独比较就行了。

  • 不过这道题最有意思还有一点就是:保存路径,其巧妙程度值得推敲
#include <iostream>#include <cstdio>#include <cstring>using namespace std;const int maxn = 1005;const int INF = 0x3f3f3f3f;int n;int a[maxn],b[maxn];int dp[maxn][maxn][2];int path[maxn][maxn][2];int main(int argc, char const *argv[]){    //freopen("in.txt","r",stdin);    while(scanf("%d",&n) != EOF) {        memset(dp,0,sizeof(dp));        memset(path,0,sizeof(path));        for(int i = 1;i <= n; i++) {            scanf("%d",&a[i]);        }        for(int j = 1;j <= n; j++) {            scanf("%d",&b[j]);        }        for(int l = 2;l <= n; l++) {            for(int i = 1;i+l-1 <= n; i++) {                int j = i + l - 1;                /*从左向右*/                int temp1 = dp[i+1][j][0] + b[i+1] - b[i];                int temp2 = dp[i+1][j][1] + b[j] - b[i];                if(temp1 <= temp2) {                    dp[i][j][0] = temp1;                    path[i][j][0] = 0;      /*定义为i到j从左走之后下一次走从左向右为0*/                }                else {                    dp[i][j][0] = temp2;                    path[i][j][0] = 1;      /*定义为i到j从左走之后下一次走从右向左为1*/                }                if(a[i] <= dp[i][j][0])     /*若低于i自动上升的是时间则为不可达*/                    dp[i][j][0] = INF;                /*从右往左*/                temp1 = dp[i][j-1][1] + b[j] - b[j-1];                temp2 = dp[i][j-1][0] + b[j] - b[i];                if(temp1 >= temp2) {                    dp[i][j][1] = temp2;                    path[i][j][1] = 0;                }                else {                    dp[i][j][1] = temp1;                    path[i][j][1] = 1;                }                if(a[j] <= dp[i][j][1])                    dp[i][j][1] = INF;            }        }        int l,r,temp;        if(dp[1][n][0] < INF) {            temp = path[1][n][0];            l = 2,r = n;            printf("1");        }        else if(dp[1][n][1] < INF) {            temp = path[1][n][1];            l = 1,r = n - 1;            printf("%d",n);        }        else {            printf("Mission Impossible\n");            continue;        }        while(l <= r) {            if(temp == 0) {                temp = path[l][r][0];                printf(" %d",l++);            }            else {                temp = path[l][r][1];                printf(" %d",r--);            }        }        printf("\n");    }    return 0;}