1. 程式人生 > >開餐館 OpenJ_Bailian - 4118 (動態規劃 + 滾動陣列)

開餐館 OpenJ_Bailian - 4118 (動態規劃 + 滾動陣列)

這題還算是一道比較基礎的動態規劃問題啦, 和01揹包問題略有類似, 都需要考慮容量和複雜度優化, 之前定義狀態總想著能二維就二維, 現在看來很多時候其實可以直接用一維的思路去定義狀態, 反而會簡便很多

定義dp[i] : 前i個地點產生的最大利潤(題目給出已排序的座標, 省去了排序)

然後考慮到對於每個地點我們都有選與不選兩種操作, 考慮需要再新增一個迴圈j : 來考慮第j個地點是否會是最優解

切記dp[i]的初始化就是d[i], 也就是到第i個地點至少的利潤, 再注意判斷相距要大於d

可得狀態轉移方程: dp[i] = dp{dp[i], dp[j] + d[i] | dp[i] - dp[j] > k}

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <cmath>
using namespace std;
#define ms(x, n) memset(x,n,sizeof(x));
typedef  long long LL;
const LL maxn = 110;

int T, n, k;
int p[maxn], m[maxn];
int dp[maxn]; //在前i個餐館裡取得的最大價值
int solve()
{
    for(int i = 1; i <= n; i++) //i表示第i個餐館
        for(int j = 1; j < i; j++){ //找到一個最大價值的位置
            if(m[i] - m[j] > k)
                dp[i] = max(dp[i], dp[j]+p[i]);
        }

    int ans = 0;
    for(int i = 1; i <= n; i++)
        ans = max(dp[i], ans);
    return ans;
}

int main()
{
    cin >> T;
    while(T--){
        cin >> n >> k;
        for(int i = 1; i <= n; i++)
            cin >> m[i];
        for(int i = 1; i <= n; i++){
            cin >> p[i];
            dp[i] = p[i];
        }
        cout << solve() << endl;
    }
    return 0;
}