[区间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;
    }
}

 

posted @ 2019-08-03 11:02  wlzs1432  阅读(125)  评论(0编辑  收藏  举报