题目
小卖部中有许多种零食,每种零食都有渴望度,且价格小数部分仅可能为0.5或0。一次只能买三包以内的零食,且价格必须是5的整数倍,求能买到的最大渴望度。
具体描述请见hihoCoder。
解题思路
动态规划。递推式:S[i,j,k] = max(S[i-1,j-1,k-m] + s[i],
S[i-1,j,k]),其中i代表零食编号,j代表购买数量,k代表总价格乘2模10。m代表s[i]*2
mod 10。
时间复杂度
时间复杂度为4*10*N,空间复杂度为4*10*N,空间复杂度可优化成4*10*2,更进一步可优化成4*10*1(考虑到递推关系中每次变化仅相差1)。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
   | #include <iostream> #include <algorithm> using namespace std;
  int mod(float p) { 	return (int) (p * 2) % 10; }
  int maxSat(float *A, int *B, int N) { 	int ***S = new int**[N]; 	for (int i = 0; i < N; i++) { 		S[i] = new int*[4]; 		for (int j = 0; j < 4; j++) { 			S[i][j] = new int[10]; 			for (int k = 0; k < 10; k++) 				S[i][j][k] = -1; 			S[i][0][0] = 0; 		} 	}
  	S[0][1][mod(A[0])] = B[0]; 	for (int i = 1; i < N; i++) { 		for (int j = 1; j < 4; j++) { 			for (int k = 0; k < 10; k++) { 				int m = (k - mod(A[i]) + 10) % 10; 				if (S[i - 1][j - 1][m] != -1) 					S[i][j][k] = S[i - 1][j - 1][m] + B[i]; 				if (S[i - 1][j][k] != -1) 					S[i][j][k] = max(S[i][j][k], S[i - 1][j][k]); 			} 		} 	}
  	int maxS = 0; 	for (int i = 0; i < 4; i++) 		maxS = max(maxS, S[N - 1][i][0]);
  	for (int i = 1; i < N; i++) { 		for (int j = 1; j < 4; j++) 			delete[] S[i][j]; 		delete[] S[i]; 	} 	delete[] S;
  	return maxS; }
  int main() { 	int Q = 0; 	cin >> Q; 	for (int i = 0; i < Q; i++) { 		int N = 0; 		cin >> N; 		float *A = new float[N]; 		int *B = new int[N]; 		for (int j = 0; j < N; j++) 			cin >> A[j] >> B[j];
  		cout << maxSat(A, B, N) << endl;
  		delete[] A, B; 	}
  	return 0; }
   |