P3049 [USACO12MAR] Landscaping S 题解
P3049 [USACO12MAR] Landscaping S
简化题意
有 \(n\) 个花盆,第 \(i\) 个花盆中原先有 \(A_i\) 单位的土。我们希望第 \(i\) 个花盆中的土变为 \(B_i\) 单位。我们可以进行这些操作:
- 购买一单位的土,放到任意一个花盆中,花费 \(X\)。
- 从任意一个花盆中删除一单位的土,花费 \(Y\)。
- 把一单位的土从花盆 \(i\) 转移到花盆 \(j\),花费为 \(Z |i - j|\)。
求满足需求的最小花费。
解题思路
这题我一开始想到的是贪心,但是太菜了实在想不出怎么解,因此想到了可以用 DP。但是这里我就一直没有推出动态规划的状态转移方程,因此只能放弃去看提示了……
然后我发现,确实题解解法的方程我是想不到的。因此就想到要记录一下。
看懂了之后,我就来讲一下这题的解题方法。
首先,弄出两个数组,大致是这样的结构:比如在 \(A\) 数组中,是 1 2 3 4,那么我们就写成这样的形式:1 2 2 3 3 3 4 4 4 4。
同样对 \(B\) 数组进行这样的操作。
然后,我们设 \(dp_{i, j}\) 为使 \(A\) 数组前 \(i\) 项变为 \(B\) 数组前 \(j\) 项所需的花费。
那么,我们可以推出这个状态转移方程(我感觉思路有点像 P2758 编辑距离):
\[dp_{i, j} = \min\{dp_{i - 1, j} + Y, dp_{i, j - 1} + X, dp_{i - 1, j - 1} + Z |i - j|\}
\]
初始化就是 \(dp_{i, 0} = i \cdot Y\), \(dp_{0, i} = i \cdot X\),\(dp_{0, 0} = 0\)。
然后按上面所说进行操作即可。
其实这个 DP 思路确实不好想,但是也算增加知识了。
代码部分
#include <bits/stdc++.h>
using namespace std;
int n, x, y, z, N = 0, M = 0;
int a[1010], b[1010];
long long dp[1010][1010];
int main()
{
cin >> n >> x >> y >> z;
for(int i = 1, A, B;i <= n;i ++)
{
cin >> A >> B;
while(A --)
a[++ N] = i;
while(B --)
b[++ M] = i;
}
memset(dp, 0x3f3f3f3f, sizeof(dp));
dp[0][0] = 0;
for(int i = 1;i <= N;i ++)
dp[i][0] = y * i;
for(int i = 1;i <= M;i ++)
dp[0][i] = x * i;
for(int i = 1;i <= N;i ++)
for(int j = 1;j <= M;j ++)
dp[i][j] = min(min(dp[i][j - 1] + x, dp[i - 1][j] + y), min(dp[i - 1][j - 1] + abs(a[i] - b[j]) * z, dp[i][j]));
cout << dp[N][M] << endl;
return 0;
}
浙公网安备 33010602011771号