P3049 [USACO12MAR]Landscaping S

本文介绍了一种简化线性动态规划问题的方法,通过数据离散化处理,便于计算土壤移动成本和展示思路。讨论了移除、添加和土壤移动三种状态的计算方式,并详细解释了特殊情况的处理,如边界条件和操作优化。核心算法展示了如何使用dp[i][j]来存储最小成本。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

This question is a classical linear dp question.

The trick to simplfy the question is to preprocess the data with a special discretized method.

We can label the soil with its id and seperate the data just like below:

original array : 1 4 5 6

discretized : 1 2 2 2 2 3 3 3 3 3 6 6 6 6 6 6

The benefits of the above operation is when you calculating the moving cost and illustrating the idea would be easier.

There are total three state:

1. removing soil: dp[i - 1][j] + y

2. adding soil: dp[i][j - 1] + x

3. shifting soil: dp[i - 1][j - 1] + z* abs(a[j] - b[j])

First, studying the removing case. It is pretty obvious, since we dont need a[i] , then just  abandon it, thus we need to inherit the i - 1 state with j remain unchanged, we have

dp[i - 1][j] + y.

Second, in the adding case, as we are making the a's array longer to match with the b[j], position i should not move, but making the length of a longer, thus j is moving, and the j comes from j - 1, we have dp[i][j] = dp[i][j - 1] + x.

P.S. the i is not moving is because we dont need to consider about where the i come from, we consider the adding operation from the cost aspect, which already added into the dp[i][j - 1].

Lastm in the shifting case, shifting is just remove a soil from previous landscape and add back the current landscape, with this idea, the state is pretty easy. With removing operation, i - 1, the adding operation j - 1, thus dp[i][j] = dp[i - 1][j - 1] + z* abs(a[i] - a[j]), the  original formula of z, is

z * |i - j|, however we already preprocessed the data, it is easy to calculate.

P.S. maybe concern about the correctness of shifting, how to shift the soil from the larger index landscape to the small index landscape? the j is a for loop from 1 to n, which includes all the possible combinations.

dp[i][j] = min(dp[i - 1][j] + y, dp[i][j - 1] + x, dp[i - 1][j - 1] + z * abs(a[i] - b[j]))

there are two cases you have to consider, which is dp[0][i] and dp[i][0], in these cases, the only operation is adding and removing, so, initilize dp[0][i] and dp[i][0] is a must.

for(int i = 1; i <= lena; i++) dp[0][i] = i * x;

for(int i = 1; i <= lenb; i++) dp[i][0] = i * y; 

#include <iostream>
#include <cstring>
using namespace std;
int n, x, y, z, lena = 1, lenb = 1;
int a[1005], b[1005];
int dp[1005][1005];
void work(){
    cin >> n >> x >> y >> z;
    for(int i = 1 , a1, b1; i <= n; i++){
        cin >> a1 >> b1; 
        while(a1--)a[lena++] = i;
        while(b1--)b[lenb++] = i;
    }
    memset(dp, 0, sizeof(dp));
    for(int i = 1; i <= lenb; i++)dp[0][i] = i * x;
    for(int i = 1; i <= lena; i++)dp[i][0] = i * y;
    for(int i = 1; i <= lena; i++){
        for(int j = 1; j <= lenb; j++){
            dp[i][j] = min(dp[i - 1][j] + y, min(dp[i - 1][j - 1] + z*abs(a[i] - b[j]), dp[i][j - 1] + x));
        }
    }
    cout << dp[lena][lenb] << endl;
}
int main(){
    work();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值