zoukankan      html  css  js  c++  java
  • [区间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;
        }
    }
  • 相关阅读:
    java基础
    C++菜鸟启动之旅--vc6.0使用教程详解
    第8章 Linux磁盘与文件系统管理
    IO(四)----对象的序列化
    IO(三)----序列流
    IO(二)----字符流
    IO(一)----字节流
    File类
    枚举类
    自动装箱和自动拆箱
  • 原文地址:https://www.cnblogs.com/wlzs1432/p/11294111.html
Copyright © 2011-2022 走看看