上决╇ф人员分配问题 (背包问题)

  题目链接--上决╇ф人员分配问题

  比赛的时候一直过不了这题。$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;
}

如有不当之处欢迎指出!

 

posted @ 2018-04-23 21:16  flyawayl  阅读(438)  评论(0编辑  收藏  举报