The Last Puzzle ZOJ

题目链接
本题也是区间dp,贪心可证,每一次出发必定是从端点,否则必然有重复,不会是最小值,那我们可以设dpi,j,0/1,0代表从左端点出发,1代表从右端点,因为每次都是从端点出发,状态方程为
dpi,j,0=min(dpi+1,j,0+d[i+1]-d[i], dpi+1,j,1+dp[j]-dp[i])分别表示from i to i+1 to j, from i to j to i+1
dpi,j,1=min(dpi,j-1,1+d[j]-d[j-1], dpi,j-1,0+dp[j]-dp[i])分别表示from j to j-1 to i, from j to i to j-1

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) ((x)&(-x))
typedef long long LL;
typedef pair<int,int> pii;

const int maxn = 205;
const int INF = 0x3f3f3f3f;
int dp[maxn][maxn][2], d[maxn], t[maxn], mov[maxn][maxn][2];

void run_case() {
    int n;
    while(cin >> n) {
        for(int i = 1; i <= n; ++i) cin >> t[i];
        for(int i = 1; i <= n; ++i) cin >> d[i];
        memset(dp, 0, sizeof(dp));
        for(int i = n-1; i >= 1; --i) {
            for(int j = i+1; j <= n; ++j) {
                
                if(dp[i+1][j][0] + d[i+1] - d[i] < dp[i+1][j][1] + d[j] - d[i]) {
                    dp[i][j][0] = dp[i+1][j][0] + d[i+1] - d[i];
                    mov[i][j][0] = 0; // from i to i+1
                } else {
                    dp[i][j][0] = dp[i+1][j][1] + d[j] - d[i];
                    mov[i][j][0] = 1; // from i to j
                }
                if(dp[i][j][0] >= t[i]) {
                    dp[i][j][0] = INF;
                }
                // calculate dp[i][j][1]
                if(dp[i][j-1][0] + d[j] - d[i] < dp[i][j-1][1] + d[j] - d[j-1]) {
                    dp[i][j][1] = dp[i][j-1][0] + d[j] - d[i];
                    mov[i][j][1] = 0; // from j to i
                } else {
                    dp[i][j][1] = dp[i][j-1][1] + d[j] - d[j-1];
                    mov[i][j][1] = 1; // from j to j-1
                }
                if(dp[i][j][1] >= t[j]) {
                    dp[i][j][1] = INF;
                }
            }
        }
        int l=0, r=-1, flag;
        if(dp[1][n][0] < INF) {
            l = 2, r = n;
            flag = mov[1][n][0];
            cout << "1";
        } else if(dp[1][n][1] < INF) {
            l = 1, r = n-1;
            flag = mov[1][n][1];
            cout << n;
        } else {
            cout << "Mission Impossible";
        }
        while(l <= r) {
            if(flag) {
                cout << " " << r;
                flag = mov[l][r][1];
                r--;
            } else {
                cout << " " << l;
                flag = mov[l][r][0];
                l++;
            }
        }
        cout << "
";
    }
}

int main() {
    ios::sync_with_stdio(false), cin.tie(0);
    cout.flags(ios::fixed);cout.precision(10);
    //int t; cin >> t;
    run_case();
    cout.flush();
    return 0;
}

何时区间dp呢?

数据范围一定
需要维护区间状态,不同区间选择造成的影响不同,石子合并,杀狼等

原文地址:https://www.cnblogs.com/GRedComeT/p/12356169.html