TOJ 3874: Landscaping -- DP

題目鏈接: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;
}

發佈了49 篇原創文章 · 獲贊 3 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章