上决╇ф人员分配问题 (背包问题)
题目链接--上决╇ф人员分配问题
比赛的时候一直过不了这题。$dp(i,j,k)$表示从前$i$个Acmer中选择$j$个能取得的最大战斗力,并且战斗力不超过$k$。
转移方程$dp(i,j,k)=max\{dp(i-1, j, k), dp(i-1, j-1, k-a[i]) + a[i]\}$,记得判断一下前驱状态是否可以到达。
AC代码
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; const int maxn = 30 + 5; int a[maxn]; int dp[maxn][maxn][1000], f[maxn][maxn][1000]; int solve(int n, int tol) { memset(dp, 0, sizeof(dp)); memset(f, 0, sizeof(f)); int sum = tol / 2; for(int i = 0; i <= n; i++) for(int k = 0; k <= sum; k++) f[i][0][k] = 1; for(int i = 1; i <= n; i++) { for(int j = 1; j <= n/2; j++) { for(int k = 1; k <= sum; k++) { dp[i][j][k] = dp[i-1][j][k]; f[i][j][k] = f[i-1][j][k]; if(k-a[i] >= 0 && f[i-1][j-1][k-a[i]] && dp[i-1][j-1][k-a[i]] + a[i] <= sum) { f[i][j][k] = 1; dp[i][j][k] = max(dp[i][j][k], dp[i-1][j-1][k-a[i]] + a[i]); } } } } return tol - 2 * dp[n][n/2][sum]; } int main() { int n; while(scanf("%d", &n) == 1) { int tol = 0; for(int i = 1; i <= 2*n; i++) { scanf("%d", &a[i]); tol += a[i]; } printf("%d\n", solve(2*n, tol)); } return 0; }
如有不当之处欢迎指出!