zzuoj 10452: "分"数 【dp】

题目链接:zzuoj 10452: “分”数

10452: “分”数
Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 111 Solved: 20
[Submit][Status][Web Board]
Description
有一个由偶数个正整数组成的无序数组,现在小D想:怎样把这个含有偶数(2*n)个数的数组分为两个元素个数相等的数组,并使得两个字数组的和最接近?

Input
有多组测试数据。
每组第一行输入一个N(N<=50且N为偶数),代表有多少个数。
接下来输入由空格隔开的N个数x(0<=x<=100)。

Output
输出每行包含两个数,分别代表分割成的两数组的和。(从小到大)

Sample Input
4
1 3 2 4
6
1 3 6 8 2 5

Sample Output
5 5
12 13

dp[i][j][k] 表示前i个数取j个和为k的状态,存在为1,反之为0;
这样写在初始化的时候会T,直接滚动数组优化下。。。
第二维开n/2,第三维开sum / 2即可。

AC代码:

#include <cstdio> 
#include <cstring> 
#include <algorithm> 
#include <iostream> 
#include <queue> 
#include <cmath> 
#include <stack> 
#include <map> 
#include <vector> 
#include <cstdlib> 
#define fi first 
#define se second 
#define ll o<<1 
#define rr o<<1|1 
#define CLR(a, b) memset(a, (b), sizeof(a)) 
using namespace std; 
typedef long long LL; 
typedef pair<int, int> pii; 
const int MOD = 1e9 + 7; 
const int MAXN = 100; 
const int INF = 1e9 + 10; 
void add(LL &x, LL y) { x += y; x %= MOD; } 
int a[51]; 
int dp[2][26][3000]; 
int main() 
{ 
    int n; 
    while(scanf("%d", &n) != EOF) { 
        int sum = 0; 
        for(int i = 1; i <= n; i++) { 
            scanf("%d", &a[i]); 
            sum += a[i]; 
        } 
        CLR(dp, 0); bool last = 1; 
        dp[last][0][0] = 1; dp[last][1][a[1]] = 1; 
        for(int i = 2; i <= n; i++) { 
            int now = !last; 
            for(int j = 0; j <= n / 2; j++) { 
                for(int k = 0; k <= sum / 2; k++) { 
                    dp[now][j][k] = dp[last][j][k]; 
                    if(k >= a[i] && j >= 1) { 
                        dp[now][j][k] |= dp[last][j-1][k-a[i]]; 
                    } 
                } 
            } 
            last = !last; 
        } 
        int sum1 = -1; 
        for(int k = sum / 2; k >= 0; k--) { 
            if(dp[last][n/2][k]) { 
                sum1 = k; 
                break; 
            } 
        } 
        printf("%d %d\n", sum1, sum - sum1); 
    } 
    return 0; 
} 

你可能感兴趣的:(zzuoj 10452: "分"数 【dp】)