題目鏈接:http://acm.tzc.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=3874
題目大意:
N(1 <= N <= 100)個數排成一行,值分別爲A_i,現在希望把每個數對應地改成B_i。(A_i,B_i的值均在0..10之間)。改變的方式有3種:
(1)把A_i增加到B_i,每增加1,花費$X
(2)把A_i減少到B_i,每減少1,花費$Y
(3)把第i個數的值轉移到第j個數,每轉移1,花費爲$Z*|i-j|
問:最小的花費是多少。
分析:用dp[i][j]表示位置i+1..n已達到要求(分別等於b[i])且位置i當前值爲j的狀態。如果j > b[i],那麼位置i要減少j - b[i],可以直接減少,也可以把減少的部分加到位置1..i-1上,枚舉就好了。j < b[i]的情況就增加。注意可能後面的位置都是a[i] > b[i],那麼多餘的部分就會不停地往前累加,所以j可能會比較大,而且可能爲負(數組下標平移就行了),開數組時注意。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define mp make_pair
#define MEMSET(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef unsigned int ui;
typedef long long ll;
typedef unsigned long long ull;
typedef pair pii;
typedef vector vi;
typedef vi::iterator vi_it;
typedef map mii;
typedef priority_queue pqi;
typedef priority_queue, greater > rpqi;
const int INF = 0X3F3F3F3F;
int dp[101][1000];
int a[101], b[101];
int x, y, z;
int cal_dp(int n, int k)
{
if (dp[n][k] != INF) {
return dp[n][k];
}
if (n == 0) {
return dp[n][k] = k - 500 > b[0] ? (k - 500 - b[0]) * y : (b[0] - k + 500) * x;
}
if (k - 500 > b[n]) {
int diff = k - 500 - b[n];
for (int i = 0; i <= diff; ++i) {
int tmp = i * y + cal_dp(n - 1, a[n - 1] + diff - i + 500) + (diff - i) * z;
if (tmp < dp[n][k]) {
dp[n][k] = tmp;
}
}
}
else {
int diff = b[n] - k + 500;
for (int i = 0; i <= diff; ++i) {
int tmp = i * x + cal_dp(n - 1, a[n - 1] - diff + i + 500) + (diff - i) * z;
if (tmp < dp[n][k]) {
dp[n][k] = tmp;
}
}
}
return dp[n][k];
}
int main(int argc, char *argv[])
{
// freopen("D:\\in.txt", "r", stdin);
MEMSET(dp, 0X3F);
int n;
cin >> n >> x >> y >> z;
for (int i = 0; i < n; ++i) {
cin >> a[i] >> b[i];
}
cout << cal_dp(n - 1, a[n - 1] + 500) << endl;
return 0;
}